Использование SmtpClient для отправления почты через SMTP сервер Яндекса с SSL

    Если вы используете Яндекс.Почту для домена, то скорее всего уже знаете что неделю назад с 16 сентября 2014 г. SMTP сервер Яндекса smtp.yandex.ru полностью перешел на SSL, о чем компания добросовестно уведомила клиентов (говорю безо всякого сарказма, действительно сработали добросовестно). В почтовой рассылке были приведены инструкции для популярных почтовых клиентов о том, какие изменения в них необходимо произвести, чтобы почта работала после перехода на SSL: Шифрование передаваемых данных. Если кратко, то в настройках SMTP надо указать порт 465 и включить опцию шифрование SSL. Однако, если у вас есть свое .Net приложение, в котором для отправления почты используется стандартный класс System.Net.Mail.SmtpClient, то при попытке использовать эти инструкции возникнет исключение с сообщением о превышении времени ожидания.

    Прочитав приведенные выше инструкции, мы могли бы ожидать, что следующий код отработает без проблем:
    var msg = new MailMessage(from, to, subj, body);
    var smtpClient = new SmtpClient("smtp.yandex.ru", 465);
    smtpClient.Credentials = new NetworkCredential(username, pwd);
    smtpClient.EnableSsl = true;
    smtpClient.Send(msg);
    

    Однако, как было отмечено выше, при попытке послать письмо генерируется исключение. Чтобы код работал, по-прежнему нужно использовать стандартный SMTP порт 25, как для незащищенных соединений, но указав при этом EnableSsl = true:
    var msg = new MailMessage(from, to, subj, body);
    var smtpClient = new SmtpClient("smtp.yandex.ru", 25);
    smtpClient.Credentials = new NetworkCredential(username, pwd);
    smtpClient.EnableSsl = true;
    smtpClient.Send(msg);
    

    Возможно, это обусловлено реализацией режима явного SSL (explicit SSL) в SmtpClient, когда соединение устанавливается через 25 порт в незашифрованном виде, а затем переключается в защищенный режим. Тем не менее, т.к. решение неочевидное, решил опубликовать его, чтобы сэкономить время тем, кто столкнется с этой проблемой.

    Similar posts

    AdBlock has stolen the banner, but banners are not teeth — they will be back

    More
    Ads

    Comments 14

      +2
      А какое исключение генерируется при отправке на 465 порт? На порту для ssl всё же точно должно работать.
      На 25ом порту во время сессии можно включить STARTTLS, видимо smtpClient ровно это и делает.

      Возможно в первом случае вы пытаетесь использовать STARTTLS под уже включенным ssl-соединением, и клиенту становится плохо:)
        +1
        > А какое исключение генерируется при отправке на 465 порт? На порту для ssl всё же точно должно работать.
        timeout exception. Работать-то через 465 порт оно может и должно, но не работает.

        > Возможно в первом случае вы пытаетесь использовать STARTTLS под уже включенным ssl-соединением, и клиенту становится плохо:)
        скорее всего так и есть, однако SmtpClient скрывает низкоуровневые детали протокола, поэтому напрямую команды SMTP посылать серверу через него нельзя. Так что этот комментарий относится скорее к тому, что происходит внутри класса. Статья была именно про то, как отправлять почту через сервер Яндекса, используя доступный интерфейса SmtpClient.

        Вообще идея про то, что что-то не так с 465 портом пришла ко мне после попыток подключится к smtp.yandex.ru через telnet:
        o smtp.yandex.ru 465
        вызывало непонятные глюки. Ошибки соединения не было, но консоль сходила с ума: каретка переводилась вначало окна и символы при печати накладывались на уже выведенный ранее текст. Сами символы команд и результатов выполнения при этом были невидимые. Хотя с 25 портом подключение было успешным:
        o smtp.yandex.ru 25
        Все это натолкнуло меня на идею попробовать код, который в итоге заработал и который я привел в статье.
          0
          На 465 порте живёт устаревший SMTPS, который подразумевает установку защищённого содениня сразу. STARTTLS работает на портах 25 и 587, фиг знает почему Яндекс это не афиширует.
      +5
      Знакомая история. Mail.ru то же теперь работает только через SSL. И там та же проблема.
      Причина из за того что SmtpClient поддерживает только Explicit SSL. Поэтому он должен сперва коннектиться к 25 порту, а потом начинать шифровать. Опять же, при условие что сервер так настроен. А если сервер настроен, чтоб получить сразу SSL/TLS, тогда без бубна отправить письмо не получиться.
      Вдруг кому пригодится:
      stackoverflow.com/questions/1011245/how-can-i-send-emails-through-ssl-smtp-with-the-net-framework
      stackoverflow.com/questions/172811/is-there-a-way-i-can-tell-whether-an-smtp-server-is-expecting-a-client-to-connect/172860#172860
        0
        Буквально сегодня исправлял приложение не Delphi. Там это решается тоже легко и просто:
        1. Кидаю на форму SSLIOHandler.
        2. Прикручиваю его хэндлером к используемому idSmtp из стандартной indy библиотеки.
        3. Свойство useTLS ставлю useRequireTLS.
        Все замечательно ходит.

        И да, порт тоже оставил 25.
          0
          > Буквально сегодня исправлял приложение не Delphi…
          > Кидаю на форму…
          эх, ностальгия
            0
            :) Именно из ностальгии и писалась программулька именно на Delphi.
            0
            Тоже вчера правил программу на Delphi для smtp.mail.ru, и тоже с Indy 10,
            у меня все работает при отправке на 465 порт, т.е. как и положено
            IdSMTP.UseTLS := utUseImplicitTLS; IdSMTP.AuthType:= satDefault;
            еще нюанс имеется один — email отправителя должен быть реальным адресом на *mail.ru, логин от которого используется для авторизации по TLS, иначе не работает.
              0
              ох, тут речь про яндекс, сорри
                0
                Само собой должен быть реальный адрес.
              0
              у меня заработало только с 587 портом. С 25 портом timeout.

              var msg = new MailMessage(from, to, subj, body);
              var smtpClient = new SmtpClient("smtp.yandex.ru", 587);
              smtpClient.Credentials = new NetworkCredential(username, pwd);
              smtpClient.EnableSsl = true;
              smtpClient.Send(msg);
              

            Only users with full accounts can post comments. Log in, please.