Ostatnio natrafiłem na ciekawy błąd. Dostałem raport, że nie udała się wysyłka maila w jednym z systemów. Oczywiście logowanie błędów było a gdy otworzyłem logi moim oczom ukazał się następujący błąd:
Klient lub serwer jest skonfigurowany tylko do obsługi adresów e-mail zawierających części lokalne w formacie ASCII.
Mając stacktrace zobaczyłem, że wyjątek leci przy SmtpClient.Send a dokładniej w metodzie MailAddress.GetUser. Uzbrojony w taką widzę wyruszyłem na poszukiwania.

Analiza

Długo szukać nie trzeba było, bo po kilku frazach wyskoczył dokładnie ten sam problem na stackoverflow. Niestety odpowiedzią tam jest, że .NET nie wspiera wysyłania maili z nazwą użytkownika niebędącą znakami ASCII. Przy okazji ciekawe jak autor założył konto z takimi znakami na gmail’u bo u mnie nie pozwala na wprowadzenie znaków innych niż ASCII (jak również żaden z dużych polskich ‘pocztowców’ – wp, onet, interia).

Trochę trudno mi było uwierzyć wiedząc w brak wsparcia UTF8, wiedząc że mogę w kodzie sobie napisać metodę Zażółćgęśląjaźń() i mi się skompiluje (ale proszę nie stosujcie takich nazw :]). W sieci nie spodziewałem się odnaleźć więcej informacji więc zasiadłem do VS. Odpaliłem kod gdzie ten Send był i F12…i dzięki magii R# i źródeł Framework’a ląduję w zdekompilowanej metodzie Send. Co ciekawe jednak nie widzę nigdzie ValidateUnicodeRequirement. Otwieram IlSpy’a i ładuję Framework’a – jest. Widzimy także, że flaga, która przekazywana jest do metody a ma dość znaczącą nazwę AllowUnicode jest ustawiana na podstawie wyniku innej funkcji – bool allowUnicode = this.IsUnicodeSupported()

private bool IsUnicodeSupported()
{
    if (this.DeliveryMethod == SmtpDeliveryMethod.Network)
    {
        return this.ServerSupportsEai && this.DeliveryFormat == SmtpDeliveryFormat.International;
    }
    return this.DeliveryFormat == SmtpDeliveryFormat.International;
}

Widzimy zatem, że aby nasz mail z utfową nazwą do odbiorcy dotarł (zakładamy, że wysyłamy przez sieć – SmtpDeliveryMethod.Network) – musimy spełnić dwa warunki. Mieć ustawiony DeliveryFormat na International oraz flaga ServerSupportsEai musi zwrócić true. Zobaczmy co się za tym kryje. Kilka przejść w ILSpy’u, kilka użyć Analyze tu i tam i mamy, że tak na prawdę interesuje nas pole serverSupportsEai na klasie SmtpPooledStream. Jeszcze kilka użyć Analyze i lądujemy w metodzie ParseExtensions. W niej to prawie pod sam koniec ustawiane jest to pole na true.

if (string.Compare(text, 0“SMTPUTF8”08, StringComparison.OrdinalIgnoreCase) == 0)
{
    ((SmtpPooledStream)this.pooledStream).serverSupportsEai = true;
}

Mając ten fragment kodu lądujemy na odpowiednim wpisie na Wikipedii gdzie możemy co nieco na ten temat przeczytać.

Podsumowując

Wygląda na to, że .NET potrafi obsłużyć UTF8 w adresach e-mail, ale muszą być spełnione dodatkowe warunki. Odpowiednio ustawiona flaga DeliveryFormat oraz serwer, który wspiera rozszerzenie SMTPUTF8, a te jak widzimy we wpisie na Wikipedii popularne nie są 🙂

Chętnie bym moje rozważania teoretyczne sprawdził w praktyce i odpowiednio skomentował pytanie na SO. Gdyby ktoś wiedział, gdzie można założyć skrzynkę z nazwą lokalną w UTF8 – dajcie znać w komentarzu.


dotnetomaniak.plNajciekawsze artykuły o .NET