Как настроить имя вложения для правильного отображения в Outlook

Я создаю электронное письмо с вложением MIME из порта отправки SMTP BizTalk 2016. Однако я думаю, что любые сведения о странностях Outlook и MIME, которыми кто-либо может поделиться с любого другого языка, могут помочь мне решить проблему, указанную ниже.

В Outlook вложение отображается как body.txt, но когда я нажимаю «Сохранить файл», отображается имя, которое я использовал при его создании (и это то, что хочет видеть пользователь).

Я имею в виду левую сторону, где написано "body.txt" над 5k и справа от значка вложения на снимке экрана ниже:

введите описание изображения здесь

В компоненте BizTalk C # Pipeline это вложение было установлено с помощью следующего кода, в котором мы устанавливаем свойства контекста в сообщении BizTalk. Я также попытался установить ContentHeader и ContentID.

strFilename = "MyFileName_693.txt";  // Just for example. 
pInMsg.BodyPart.PartProperties.Write(
              "FileName",
              "http://schemas.microsoft.com/BizTalk/2003/mime-properties",
               strFilename);

Когда я переслал письмо на свой Gmail, вложение было показано с правильным именем. Поэтому мой вопрос касается того, чтобы он отображался с желаемым именем в Outlook (2016).


person NealWalters    schedule 11.05.2017    source источник
comment
См. social.msdn.microsoft.com/Forums/en-US/ и stackoverflow.com/questions/39407158/ Вы также устанавливаете свойство (MIME.FileName)?   -  person Dijkgraaf    schedule 12.05.2017
comment
Мой вопрос почти дублирует тот, за исключением того, что я нахожусь в компоненте конвейера, а он - в оркестровке. В моем коде выше показано, как вы устанавливаете MIME.FileName в конвейере. Ссылка MSDN дала мне эту подсказку, которую я собираюсь попробовать: И после этого убедитесь, что вы добавляете свой настраиваемый компонент конвейера после компонента MIME Encoder на этапе кодирования конвейера отправки. Я пробовал это после, но не раньше!   -  person NealWalters    schedule 15.05.2017
comment
MSDN - та же проблема, но он тоже находится в оркестровке; они говорят об использовании динамического конвейера. Но пока у меня есть решение для маршрутизации на основе контента без оркестровок. Я попробовал кодировщик MIME, и результаты ухудшились, вложение тогда называлось Attachment, когда я выполнял сохранение файла. Похоже, это связано с более поздними версиями Outlook, так как в GMail все выглядит нормально. В MSN Post он показывал Outlook 2013 и Outlook 2016.   -  person NealWalters    schedule 15.05.2017
comment
Все еще не получил, чтобы он работал, собираюсь попробовать оркестровку в соответствии с этим примером, чтобы увидеть, произойдет ли что-нибудь по-другому. Но мне очень хотелось сделать это в Pipeline.   -  person NealWalters    schedule 16.05.2017
comment
Если вы заставите его работать через оркестровку, вы можете сравнить созданные сообщения MIME и увидеть, в чем разница. Тогда можно будет применить это и к компоненту конвейера.   -  person Dijkgraaf    schedule 17.05.2017
comment
Получил эту работу над BT2016 в декабре 2020 года. См. Также: stackoverflow.com/questions/65509140/ и stackoverflow.com/questions/65480570/   -  person NealWalters    schedule 30.12.2020


Ответы (1)


Пока у меня это работает с оркестровкой с динамическим портом отправки. Это все еще немного работы, но она справляется со стандартным компонентом. Следующее описание основано на стандартном SMTP-адаптере, включенном в BizTalk 2013R2.

Примечание: хотя мое решение работает, оно похоже на обходной путь, и мне не следовало бы делать это, если бы адаптер был немного умнее в этом.

Прежде всего, давайте рассмотрим пример кода электронной почты, который вызывает проблемы у некоторых клиентов:

------=_NextPart_000_0001_01D4502F.8A6A1500
Content-Transfer-Encoding: 7bit
Content-Type: text/plain; charset="utf-8"

See attached email.
------=_NextPart_000_0001_01D4502F.8A6A1500
Content-Type: application/pdf; name="CDM_Order - Copy.pdf"
Content-Disposition: attachment; filename="CDM_Order - Copy.pdf"
Content-Description: body
Content-Transfer-Encoding: base64

JVBERi0xLjQKJeLjz9MNCjUgMCBvYmoKPDwvRFsgMyAwIFIvWFlaIG51bGwgODQxLjg4OTc3IG51
bGwgXQo+PgplbmRvYmoKOCAwIG9iago8PC9EWyAzIDAgUi9YWVogbnVsbCAyOTAuMjM2NTcgbnVs
bCBdCj4+ (etc etc base64 your file)...

Обратите внимание на часть Content-Description: body. По этой причине некоторые клиенты читают body.xml или, в моем случае, body.pdf, хотя часть Disposition выглядит отлично: Content-Disposition: attachment; filename="CDM_Order - Copy.pdf".

Жесткая установка MIME.FileName не просто сработает, даже если она в конечном итоге установит Content-Disposition правильно, она никогда не обновит Content-Description. Это связано с тем, что либо для статического порта отправки вы установили Attach only body part, либо вы указали соответствующее числовое значение 1 для динамического порта отправки.

Однако он будет работать со значением Attach all parts или 2 для типа MessagePartsAttachments. Это включает в себя создание сообщения, состоящего из нескольких частей, в вашей оркестровке. Он будет состоять из двух частей;

  • Первый - это BodyPart, теперь он будет включать в себя текст сообщения, а не вложение. Убедитесь, что вы указали этот параметр как Message Body Part в Message Type.
  • Вторая часть будет вашим фактическим вложением, укажите этот тип в соответствии с вашим типом вложения. В этом примере я назвал это Attachment.

Теперь вы можете подумать, что он также отправит BodyPart как вложение, поскольку я сказал, что нам нужен Attach all parts. Это правда, поэтому, чтобы исправить это, ваш BodyPart должен быть определен как RawString, это превращает строку в простой текст в части сообщения BizTalk. Для полноты картины я помещу класс C # внизу для справки.

Теперь, когда он определен как RawString, адаптер SMTP поместит его как тело, а не как вложение. В качестве побочного эффекта адаптер SMTP больше не будет помещать часть Content-Description: body во вложенную часть, а вместо этого будет помещать ее в фактическую часть тела. Выглядит это так:

------=_NextPart_000_0001_01D450E4.A7E9A5E0
Content-Transfer-Encoding: 7bit
Content-Type: text/plain; charset="utf-8"
Content-Description: body

See attached email.
------=_NextPart_000_0001_01D450E4.A7E9A5E0
Content-Type: application/pdf; name="ID_0_Nummer_0.pdf"
Content-Disposition: attachment; filename="ID_0_Nummer_0.pdf"
Content-Transfer-Encoding: base64

JVBERi0xLjQKJeLjz9MNCjUgMCBvYmoKPDwvRFsgMyAwIFIvWFlaIG51bGwgODQxLjg4OTc3IG51
bGwgXQo+PgplbmRvYmoKOCAwIG9iago8PC9EWyAzIDAgUi9YWVogbnVsbCAyOTAuMjM2NTcgbnVs
bCBdCj4+ (etc etc base64 your file)...

На самом деле ничем не отличается, кроме размещения Content-Description: body части, именно то, что мы хотим. Теперь письмо подходит каждому клиенту.

Для правильной работы необходимо также установить наиболее важные свойства, помимо тех, о которых я уже упоминал:

Тип содержимого вашего тела:

MsgPdfOrder.BodyPart(Microsoft.XLANGs.BaseTypes.ContentType) = "text/plain";

Тип содержимого вашего вложения:

MsgPdfOrder.Attachment(Microsoft.XLANGs.BaseTypes.ContentType) = "application/pdf";

Имя файла вложения:

MsgPdfOrder.Attachment(MIME.FileName) =  "CDM_Order - Copy.pdf"

Набор символов тела (если не задан, будет Unknown Error Description):

MsgPdfOrder(SMTP.EmailBodyTextCharset) = "UTF-8";

Убедитесь, что вы не установили SMTP.EmailBodyText, потому что у нас уже есть BodyPart для этого.

RawString, используйте его в оркестровке MsgPdfOrder.BodyPart = new Yournamespace.Components.RawString("See attached email.");:

using System.Runtime.Serialization;
using System;
using System.IO;
using System.Text;
using System.Xml.Serialization;
using Microsoft.XLANGs.BaseTypes;

namespace Yournamespace.Components
{
    public abstract class BaseFormatter : IFormatter
    {
        public virtual SerializationBinder Binder
        {
            get { throw new NotSupportedException(); }
            set { throw new NotSupportedException(); }
        }

        public virtual StreamingContext Context
        {
            get { throw new NotSupportedException(); }
            set { throw new NotSupportedException(); }
        }

        public virtual ISurrogateSelector SurrogateSelector
        {
            get { throw new NotSupportedException(); }
            set { throw new NotSupportedException(); }
        }

        public abstract void Serialize(Stream stm, object obj);
        public abstract object Deserialize(Stream stm);
    }

    public class RawStringFormatter : BaseFormatter
    {
        public override void Serialize(Stream s, object o)
        {
            RawString rs = (RawString)o;
            byte[] ba = rs.ToByteArray();
            s.Write(ba, 0, ba.Length);
        }

        public override object Deserialize(Stream stm)
        {
            StreamReader sr = new StreamReader(stm, true);
            string s = sr.ReadToEnd();
            return new RawString(s);
        }
    }

    [CustomFormatter(typeof(RawStringFormatter))]
    [Serializable]
    public class RawString
    {
        [XmlIgnore]
        string _val;

        public RawString(string s)
        {
            if (null == s)
                throw new ArgumentNullException();
            _val = s;
        }

        public RawString()
        {
        }

        public byte[] ToByteArray()
        {
            return Encoding.UTF8.GetBytes(_val);
        }

        public override string ToString()
        {
            return _val;
        }
    }
}
person r3verse    schedule 20.09.2018
comment
Большой! Я больше даже не работаю с этим клиентом; но уверен, что ваш ответ будет кому-то полезен в будущем. - person NealWalters; 21.09.2018
comment
Сейчас пробую еще раз на другом клиенте. Только что опубликовал связанную проблему: я опубликовал новую связанную проблему. Когда я пытаюсь установить contentType, я получаю ошибку времени выполнения. stackoverflow.com/questions/65480570/ - person NealWalters; 28.12.2020