Amazon Ses PHP SDK 2 - Как добиться высокой скорости отправки
Отправка электронных писем с использованием метода sendEmail
класса SesClient
из PHP SDK в настоящее время занимает около половины секунды на одно электронное письмо. Я просматриваю массив получателей и устанавливаю свойство message ToAddresses
равным массиву, содержащему только адрес электронной почты получателя, перед вызовом sendEmail()
. Я хотел бы ускорить процесс отправки, но мне кажется, что класс PHP, предоставляемый SDK, выполняет один запрос на сообщение (в моем случае, получатель). (Возможно, одно соединение на сообщение?)
Я немного почитал и подумал об использовании свойства BccAddresses
для отправки электронных писем партиями, но мы хотели бы, чтобы заголовок To:
был явно задан, а не просто "нераскрытые получатели", поэтому я хотел бы знать, есть ли у кого-нибудь лучший подход.
2 answers
Что я делал с PHP и AWS в прошлом, так это настраивал очередь электронной почты в бд и заставлял несколько процессов работать с ней для доставки электронных писем.
В качестве альтернативы вы можете просто доставлять электронные письма в нескольких потоках (возможно, нетривиальных в PHP). Вот пример в ruby с aws-sdk-ruby.
require aws-sdk
ses = AWS::SimpleEmailService.new(:access_key_id => 'ACCESS_KEY', :secret_access_key => 'SECRET_KEY')
pool = Array.new(ses.quotas[:max_send_rate]) do |i|
Thread.new do
ses.send_email(
:subject => 'subject',
:body_html => 'body_html',
:body_text => 'body_text',
:to => '[email protected]',
:source => '[email protected]',
)
end
end
sleep(1)
pool.each(&:join)
Для тех, кто сталкивается с AWS и SES, пытаясь решить эту проблему параллельных запросов, выполняемых при постоянном подключении, AWS SDK 2 и выше поддерживает это в php с использованием командных объектов.
Клиент SesClient и другие клиенты могут выполнять команды параллельно. Это обычный метод для запуска одного соединения и отправки электронной почты через SES:
$result = $client->sendEmail(array(
//email data
));
Клиентские объекты очень мощные и наследуют множество методов для выполнения запросов и управления ими такие как getCommand()
и execute()
. Потребовалось много часов копания, прежде чем я нашел простое решение! Вам просто нужно знать, что нужно искать. Вот пример:
$commands = array();
$commands[] = $sesClient->getCommand('SendEmail', array(
//email data
));
$commands[] = $sesClient->getCommand('SendEmail', array(
//email data
));
// Execute an array of command objects to do them in parallel
$sesClient->execute($commands);
// Loop over the commands, which have now all been executed
foreach ($commands as $command) {
$result = $command->getResult();
// Do something with result
}
Обработка ошибок может быть достигнута путем выполнения следующего кода:
use Guzzle\Service\Exception\CommandTransferException;
try {
$succeeded = $client->execute($commands);
} catch (CommandTransferException $e) {
$succeeded = $e->getSuccessfulCommands();
echo "Failed Commands:\n";
foreach ($e->getFailedCommands() as $failedCommand) {
echo $e->getExceptionForFailedCommand($failedCommand)->getMessage() . "\n";
}
}
Amazon документирует эти примеры в своем руководстве для разработчиков в разделе функция команд.