【问题标题】:how can I fix/avoid this smtp error using swift_mailer?如何使用 swift_mailer 修复/避免此 smtp 错误?
【发布时间】:2012-06-19 07:18:46
【问题描述】:

对不起,可能只是一个新手问题,但这里是, 我有一个脚本可以循环使用这样的代码发送电子邮件的一堆(有时是数千个)成员:

    $transport = Swift_SmtpTransport::newInstance('...', 25)
                                ->setUsername('...')
                                ->setPassword('...');

                $mailer = Swift_Mailer::newInstance($transport);
                $mailer->send($message);

它通常运行良好,但有时我会收到此错误: 预期响应代码 354,但得到代码“250”,消息“250 2.1.5 ... 收件人正常”

我不太了解 smtp,所以我只能猜测正在发生的事情是在发送邮件过程开始时预期会出现 354 代码,但 250 代码是从最后发送的电子邮件中收到的 - 所以邮件程序正在由于使用太快而超载,我想我应该等待每封电子邮件真正完成(即等待 250 代码),然后再发送下一封。我不想在每封电子邮件之后只粘贴一个睡眠命令,那么有没有更好的方法来防止这个错误?还是其他原因?

谢谢

【问题讨论】:

  • 我偶尔添加了一个 $mailer->disconnect() - sleep - reconnect,但这会引发错误:PHP 致命错误:调用未定义的方法 Swift_Mailer::disconnect(),我猜是 disconnect()不是 swift mailer 4.0.5 中 api 的一部分。还有其他方法吗?

标签: smtp send swiftmailer mailer


【解决方案1】:

总结:

  1. 要做的主要更改:重用您的邮件连接,最好是创建消息,所以它只在需要时完成,通常只做一次
  2. 检查您如何实例化 SwiftMailer 并确认它是最佳方式
  3. 您的 SwiftMailer 类版本似乎有点旧 (4.0.5),您可以查看更新的版本

更详细:

重用实例化对象。您每次都在重新创建邮件传输,从而导致开销。你不应该那样做。如果支持,您可以将 batchSend() 用于大量电子邮件。请参阅this question 中的使用示例。一个应用例子:

$message = Swift_Message::newInstance(...)
  ->setSubject('A subject')
  ->setFrom(array('myfrom@domain.com' => 'From Me'))
  ->setBody('Your message')
;

while(list($targetadd, $targetname) = each($targetlist))
{
   $message->addTo($targetadd, $targetname);
}

$message->batchSend();

请注意,虽然 batchSend() 是 removed in 4.1.0 RC1 of SwiftMailer。据我所知,它是internally called send() in a loop,所以你应该能够通过多次调用 send() 来获得相同的效果,但至少要重用你的邮件传输,这样你就不会每次都重新实例化它(如果适用,也创建消息)。

official documentation 的批量发送示例中,您可以使用 send() 来批量发送电子邮件

// Create the Transport
$transport = Swift_SmtpTransport::newInstance('localhost', 25);

// Create the Mailer using your created Transport
$mailer = Swift_Mailer::newInstance($transport);

// Create a message
$message = Swift_Message::newInstance('Wonderful Subject')
  ->setFrom(array('john@doe.com' => 'John Doe'))
  ->setBody('Here is the message itself')
  ;

// Send the message
$failedRecipients = array();
$numSent = 0;
$to = array('receiver@domain.org', 'other@domain.org' => 'A name');

foreach ($to as $address => $name)
{
  if (is_int($address)) {
    $message->setTo($name);
  } else {
    $message->setTo(array($address => $name));
  }

  $numSent += $mailer->send($message, $failedRecipients);
}

传输协议。 另外要注意的是 SwiftMailer 是一个包装类。它在引擎盖下实际使用的是您定义的内容。在您的情况下,您使用的是 SMTP 传输,它比邮件传输(mail() 函数)更好,但可能不是最优化的。

你没有说你是否明确想要使用它以及你有哪个环境,但是在 linux 环境中,你可以直接调用 sendmail 类似的东西

$transport = Swift_SendmailTransport::newInstance('/usr/sbin/sendmail -bs');

这可以提供更好的性能。 SwiftMailer usage documentation 有更多关于不同传输的信息。

类版本。根据您的评论,您使用的是 4.0.5 版本。当前版本是4.1.8.,自从批量发送以来,有些东西已经改变了,所以你可能也想看看。

编辑:关于 batchSend()、当前版本和手动链接的更新信息。

【讨论】:

  • 感谢您的回复,我使用 smtp,因为它是我们其他脚本使用它的标准方式,而且似乎是 swift mailer 文档推荐的。我只是偶尔重新创建传输和邮件对象,并且只是开始尝试解决这个问题,但我知道看起来我每次都在我的代码 sn-p 中这样做。所以我的代码基本上是你建议的,除了我每次都会重新创建大部分消息,因为它因收件人而异。我会考虑升级到最新版本,但我需要让系统管理员这样做。
  • 好吧,您至少可以尝试看看使用不同的传输方式是否会有所不同 - 这将有助于缩小问题范围。
  • 我还会在错误发生时重新创建传输和邮件对象,并在每个错误后运行 sleep(30) 调用,以让 smtp 服务器有时间赶上。到目前为止,这似乎工作得很好。当我有另一个机会回到这个问题时,我会尝试不同的传输方法。谢谢eis。
猜你喜欢
  • 1970-01-01
  • 2019-08-15
  • 1970-01-01
  • 2014-06-03
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2015-11-18
  • 1970-01-01
相关资源
最近更新 更多