lost baby
lost baby

Reputation: 3268

how can I fix/avoid this smtp error using swift_mailer?

Sorry, probably just a newbie question but here goes, I have a script that loops over a bunch ( sometimes thousands ) of members sending out email using code like so:

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

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

and it usually works well, but sometimes I get this error: Expected response code 354 but got code "250", with message "250 2.1.5 ... Recipient ok

I don't know smtp well so I can only guess that what is happening is the 354 code is expected at the beginning of the send mail process but the 250 code is recieved from the last email sent - so the mailer is getting getting overloaded by being used too fast, I guess I should be waiting for each email to get truly finished (ie wait for the 250 code) before sending the next. I'd hate to just stick a sleep command after each email so is there a better way to protect against this error? Or is the cause something else?

Thanks

Upvotes: 3

Views: 3294

Answers (1)

eis
eis

Reputation: 53462

In summary:

  1. Main change to do: reuse your mail connection, and preferrably creation of message, so it is done only as needed, usually just once
  2. Check how you instantiate SwiftMailer and confirm it's the most optimal way
  3. Your SwiftMailer class version seems a bit old (4.0.5), you might check out more recent version

In more detail:

Reusage of instantiated objects. You are recreating your mail transport every time, causing overhead. You shouldn't be doing that. You can use batchSend() for big bunches of emails if it is supported. See example of usage in this question. An applied example:

$message = Swift_Message::newInstance(...)
  ->setSubject('A subject')
  ->setFrom(array('[email protected]' => 'From Me'))
  ->setBody('Your message')
;

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

$message->batchSend();

Note though that batchSend() has been removed in 4.1.0 RC1 of SwiftMailer. As far as I know though, it internally called send() in a loop, so you should be able to have the same effects with calling send() multiple times but reusing at least your mail transport so you wouldn't reinstantiate it every time (and if applicable, also creation of message).

From the batch sending example at the official documentation, you can send emails in a batch by using send() with

// 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('[email protected]' => 'John Doe'))
  ->setBody('Here is the message itself')
  ;

// Send the message
$failedRecipients = array();
$numSent = 0;
$to = array('[email protected]', '[email protected]' => '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);
}

Transport protocols. Another thing to note is that SwiftMailer is a wrapper class. What it actually uses under the hood is what you define. In your case you are using SMTP transport, which is better than Mail transport (mail() function), but possibly not the most optimal one.

You don't say if you explicitly want to use that and which environment you have, but in linux environment, you could invoke sendmail directly with something like

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

Which could give a better performance. There is more information on different transports in SwiftMailer usage documentation.

Class version. Based on your comment, you are using 4.0.5 version. Current version is 4.1.8., and there are things that have been changed since with batch sending, so you might want to check that out too.

EDIT: updated info about batchSend(), current version and manual links.

Upvotes: 1

Related Questions