Amazon SES перестает работать

Я установил Amazon SES, и сначала он работал несколько часов, а затем внезапно остановился. Все электронные письма, которые я отправляю, и наш домен были проверены. Мы не рассылаем массовые электронные письма - всего несколько сотен в день. Всякий раз, когда я вношу изменения в web.config, кажется, что он снова работает еще 2-3 часа. Например, он перестал работать, поэтому я переключил порт 587 на 25, и он начал работать в течение 2-3 часов, а затем перестал. Затем я переключился обратно на 587, и произошло то же самое. Как только он перестанет работать, он никогда не запустится снова сам по себе. Он работает на двух серверах с балансировкой нагрузки, asp.net framework v2.0, IIS 7.5. Вот код, который я использую:

веб.конфигурация:

<system.net>
  <mailSettings>
    <smtp deliveryMethod="Network" from="[email protected]">
      <network defaultCredentials="false" host="email-smtp.us-east-1.amazonaws.com" userName="***" password="***" port="587" />
    </smtp>
  </mailSettings>
</system.net>

С# код:

var smtpClient = new SmtpClient() { EnableSsl = true };

var mailMessage =
    new MailMessage(fromAddress, toAddress, subject, body)
    {
        IsBodyHtml = true
    };

smtpClient.Send(mailMessage);

Вот две ошибки, которые я получал:

The following exception was thrown by the web event provider '(null)' in the application '/' (in an application lifetime a maximum of one exception will be logged per provider instance):

System.Web.HttpException: Unable to send out an e-mail to the SMTP server. Please ensure that the server specified in the <smtpMail> section is valid. ---> System.Net.Mail.SmtpException: Failure sending mail. ---> System.IO.IOException: Received an unexpected EOF or 0 bytes from the transport stream.
   at System.Net.FixedSizeReader.ReadPacket(Byte[] buffer, Int32 offset, Int32 count)
   at System.Net.Security.SslState.StartReadFrame(Byte[] buffer, Int32 readBytes, AsyncProtocolRequest asyncRequest)
   at System.Net.Security.SslState.StartReceiveBlob(Byte[] buffer, AsyncProtocolRequest asyncRequest)
   at System.Net.Security.SslState.ForceAuthentication(Boolean receiveFirst, Byte[] buffer, AsyncProtocolRequest asyncRequest)
   at System.Net.Security.SslState.ProcessAuthentication(LazyAsyncResult lazyResult)
   at System.Threading.ExecutionContext.runTryCode(Object userData)
   at System.Runtime.CompilerServices.RuntimeHelpers.ExecuteCodeWithGuaranteedCleanup(TryCode code, CleanupCode backoutCode, Object userData)
   at System.Threading.ExecutionContext.Run(ExecutionContext executionContext, ContextCallback callback, Object state)
   at System.Net.TlsStream.ProcessAuthentication(LazyAsyncResult result)
   at System.Net.TlsStream.Write(Byte[] buffer, Int32 offset, Int32 size)
   at System.Net.PooledStream.Write(Byte[] buffer, Int32 offset, Int32 size)
   at System.Net.Mail.SmtpConnection.Flush()
   at System.Net.Mail.ReadLinesCommand.Send(SmtpConnection conn)
   at System.Net.Mail.SmtpConnection.GetConnection(String host, Int32 port)
   at System.Net.Mail.SmtpClient.Send(MailMessage message)
   --- End of inner exception stack trace ---
   at System.Net.Mail.SmtpClient.Send(MailMessage message)
   at System.Web.Management.MailWebEventProvider.SendMail(MailMessage msg)
   --- End of inner exception stack trace ---
   at System.Web.Management.MailWebEventProvider.SendMail(MailMessage msg)
   at System.Web.Management.SimpleMailWebEventProvider.SendMessageInternal(WebBaseEventCollection events, Int32 notificationSequence, Int32 begin, DateTime lastFlush, Int32 discardedSinceLastFlush, Int32 eventsInBuffer, Int32 messageSequence, Int32 messagesInNotification, Int32 eventsInNotification, Int32 eventsLostDueToMessageLimit)
   at System.Web.Management.SimpleMailWebEventProvider.SendMessage(WebBaseEvent eventRaised)
   at *****.Global.SimpleMailWithSslWebEventProvider.ProcessEvent(WebBaseEvent raisedEvent)
   at System.Web.Management.WebBaseEvent.RaiseInternal(WebBaseEvent eventRaised, ArrayList firingRuleInfos, Int32 index0, Int32 index1)

The following exception was thrown by the web event provider '(null)' in the application '/' (in an application lifetime a maximum of one exception will be logged per provider instance):

System.Web.HttpException: Unable to send out an e-mail to the SMTP server. Please ensure that the server specified in the <smtpMail> section is valid. ---> System.Net.Mail.SmtpException: Service not available, closing transmission channel. The server response was: Timeout waiting for data from client.
   at System.Net.Mail.MailCommand.CheckResponse(SmtpStatusCode statusCode, String response)
   at System.Net.Mail.SmtpTransport.SendMail(MailAddress sender, MailAddressCollection recipients, String deliveryNotify, SmtpFailedRecipientException& exception)
   at System.Net.Mail.SmtpClient.Send(MailMessage message)
   at System.Web.Management.MailWebEventProvider.SendMail(MailMessage msg)
   --- End of inner exception stack trace ---
   at System.Web.Management.MailWebEventProvider.SendMail(MailMessage msg)
   at System.Web.Management.SimpleMailWebEventProvider.SendMessageInternal(WebBaseEventCollection events, Int32 notificationSequence, Int32 begin, DateTime lastFlush, Int32 discardedSinceLastFlush, Int32 eventsInBuffer, Int32 messageSequence, Int32 messagesInNotification, Int32 eventsInNotification, Int32 eventsLostDueToMessageLimit)
   at System.Web.Management.SimpleMailWebEventProvider.SendMessage(WebBaseEvent eventRaised)
   at *****.Global.SimpleMailWithSslWebEventProvider.ProcessEvent(WebBaseEvent raisedEvent)
   at System.Web.Management.WebBaseEvent.RaiseInternal(WebBaseEvent eventRaised, ArrayList firingRuleInfos, Int32 index0, Int32 index1)

Я пытался получить помощь на форумах Amazon, но безуспешно. Кажется, что-то мешает соединению, но я не знаю, что. Любые идеи? Спасибо.


person StronglyTyped    schedule 28.01.2013    source источник


Ответы (3)


Это действительно звучит как сложная проблема — я не уверен на 100% в этом, но вы, похоже, упускаете возможность избавиться от SMTP-клиента, который упоминается в Отправка электронной почты часто происходит очень медленно после перехода на экземпляр VPC, что вызывает ту самую ошибку, которую вы видите:

Когда я не удаляю SmtpClient, я получаю сообщение об ошибке...

«Служба недоступна, канал передачи закрыт. Ответ сервера был: Тайм-аут ожидания данных от клиента».

На самом деле это было бы хорошим объяснением периодически возникающих проблем, т. е. в зависимости от пути исполняемого кода эта проблема может инициировать SMTP-соединение с Amazon SES зависает, что, очевидно, лечится переключением на другой порт, что подразумевает сброс соединения - вот что пишет Метод SmtpClient.Dispose также обеспечивает:

Отправляет сообщение QUIT на SMTP-сервер, изящно завершает TCP-соединение и освобождает все ресурсы, используемые текущим экземпляром SmtpClient.

Соответственно, подходящим шаблоном будет упрощение использования оператора, как показано в Начало работы с Amazon SES и .NET:

  String username = "SMTP-USERNAME";  // Replace with your SMTP username.
  String password = "SMTP-PASSWORD";  // Replace with your SMTP password.
  String host = "email-smtp.us-east-1.amazonaws.com";
  int port = 25;

  using (var client = new System.Net.Mail.SmtpClient(host, port))
  {
    client.Credentials = new System.Net.NetworkCredential(username, password);
    client.EnableSsl = true;

    client.Send
    (
              "[email protected]",  // Replace with the sender address.
              "[email protected]",    // Replace with the recipient address.
              "Testing Amazon SES through SMTP",              
              "This email was delivered through Amazon SES via the SMTP end point."
    );
  }

Обратите внимание, что в примере используется порт 25, которого я настоятельно рекомендую избегать из-за обычно подразумеваемых ограничений на отправку. Подробнее о соответствующем регулировании Amazon EC2 см. в дополнении ниже.

Удачи!


Приложение

Amazon EC2 регулирует порт 25

Вы, вероятно, знаете об этом (и я на самом деле не думаю, что это проблема здесь), но Amazon EC2 устанавливает ограничения по умолчанию на отправку электронной почты, отправляемой через порт 25, и блокирует исходящие соединения, если вы пытаетесь превысить эти ограничения, которые по-прежнему применяются при использовании Amazon SES, см. Проблемы Amazon SES SMTP:

Вы отправляете в Amazon SES из инстанса Amazon EC2 через порт 25 и не можете достичь пределов отправки Amazon SES или получаете тайм-ауты — Amazon SES EC2 налагает ограничения по умолчанию на отправку электронной почты, отправляемой через порт 25. и блокирует исходящие соединения, если вы пытаетесь превысить эти ограничения. Чтобы снять эти ограничения, отправьте Запрос на снятие ограничений на отправку электронной почты. Вы также можете подключиться к Amazon SES через порт 465 или порт 587, ни один из которых не регулируется.

Следовательно, я бы удалил порт 25 из вашего сценария тестирования/переключения и вместо этого использовал только порты 465/587, чтобы избежать ложных выводов (как цитируется, вы также можете запросить снятие этого ограничения, но это займет несколько часов и порт 25, по-видимому, лучше избегать в первую очередь) - немного жаль, что несколько официальных образцов Amazon SES используют порт 25, даже не упоминая об этой легко инициируемой проблеме.

person Steffen Opel    schedule 29.01.2013
comment
Спасибо за ответ, я переключусь на порт 587. Я согласен, что это похоже на проблему сброса соединения, но SmtpClient на самом деле не является одноразовым в среде 2.0. Возможно, это проблема, и в этом случае мне нужно найти обходной путь. - person StronglyTyped; 29.01.2013
comment
Пришлось отказаться от решения Amazon, так как мы не смогли заставить его работать своевременно. Я отметил это как ответ, потому что думаю, что эти решения, вероятно, решат проблемы, которые могут возникнуть у других. Microsoft Exchange увеличил свои лимиты на отправку, поэтому мы используем их вместо них — раньше они были установлены слишком низко, поэтому мы изучили вариант Amazon. - person StronglyTyped; 08.08.2013
comment
У меня была точно такая же проблема, и хотя я был на .Net 4, я понятия не имел, что SmtpClient теперь одноразовый. Как только я переключился на оператор using, все стало работать НАМНОГО плавнее. Хорошая находка! - person Scott Salyer; 29.01.2014
comment
Утилизация SmtpClient тоже помогла мне. Я думал, что мы могли бы использовать довольно долгое время жизни для этого объекта, но вместо этого оно должно быть довольно коротким. - person heneryville; 11.07.2014

Хотя этот вопрос относится к .NET v2.0, недавно я столкнулся с этой проблемой и в .NET v4.5. Даже после добавления использования SMTP-клиента (как было предложено в предыдущих сообщениях) я все еще периодически получал эту ошибку. После многих часов исследований я обнаружил, что AWS поддерживает порт STARTTLS (2587; http://docs.aws.amazon.com/ses/latest/DeveloperGuide/smtp-connect.html) и, очень мелким шрифтом, Microsoft указывает, когда «EnableSsl» имеет значение true на SMTP-клиенте, клиент ожидает сеанс STARTTLS (https://msdn.microsoft.com/en-us/library/system.net.mail.smtpclient.enablessl(v=vs.110).aspx). Таким образом, после обновления моего порта до 2587 и окружения SmtpClient в «использовании {}» я смог успешно отправить ~ 20 000 электронных писем без воспроизведения ошибки.

Таким образом, рабочая конфигурация будет такой:

<system.net>
  <mailSettings>
    <smtp deliveryMethod="Network">
      <network host="email-smtp.us-west-2.amazonaws.com" port="2587" enableSsl="true" password="password" />
    </smtp>
  </mailSettings>
</system.net>

Один отказ от ответственности заключается в том, что я до сих пор не полностью понимаю истинную конфигурацию SMTP-клиента AWS или .NET, поэтому это все еще немного косвенно.

person Grady G Cooper    schedule 20.10.2015

person    schedule
comment
Единственное отличие вашего кода от моего: enableSsl=true. Это свойство не поддерживается в конфигурации для фреймворка версии 2.0, который я использую, но вы можете видеть, что оно добавляется, когда объект SmtpClient инициализируется в моем коде С#. - person StronglyTyped; 28.01.2013