PHP发送大量电子邮件到Amazon SES

3
我有一个在线软件,用于向Amazon SES发送电子邮件。目前,我有一个cron工作,使用phpmailer通过SMTP发送邮件。目前,我必须将发送限制增加到每分钟约300封电子邮件,以确保我的服务器不会超时。随着发展,我希望能够发送10,000封或更多的电子邮件。

是否有更好的方法来向Amazon SES发送电子邮件,或者这是其他人所做的,只是用更多的服务器来运行工作负载?

提前致谢!

3个回答

7

您可以尝试使用AWS SDK for PHP。您可以通过SES API发送电子邮件,而SDK使您可以并行发送多个电子邮件。以下是一个示例代码(未经测试且仅部分完整),可帮助您入手。

<?php

require 'vendor/autoload.php';

use Aws\Ses\SesClient;
use Guzzle\Service\Exception\CommandTransferException;

$ses = SesClient::factory(/* ...credentials... */);

$emails = array();
// @TODO SOME SORT OF LOGIC THAT POPULATES THE ABOVE ARRAY

$emailBatch = new SplQueue();
$emailBatch->setIteratorMode(SplQueue::IT_MODE_DELETE);

while ($emails) {
    // Generate SendEmail commands to batch
    foreach ($emails as $email) {
        $emailCommand = $ses->getCommand('SendEmail', array(
            // GENERATE COMMAND PARAMS FROM THE $email DATA
        ));
        $emailBatch->enqueue($emailCommand);
    }

    try {
        // Send the batch
        $successfulCommands = $ses->execute(iterator_to_array($emailBatch));
    } catch (CommandTransferException $e) {
        $successfulCommands = $e->getSuccessfulCommands();
        // Requeue failed commands
        foreach ($e->getFailedCommands() as $failedCommand) {
            $emailBatch->enqueue($failedCommand);
        }
    }

    foreach ($successfulCommands as $command) {
        echo 'Sent message: ' . $command->getResult()->get('MessageId') . "\n";
    }
}

// Also Licensed under version 2.0 of the Apache License.

你还可以尝试使用Guzzle的BatchBuilder和相关工具来提高代码的稳定性。
这段代码需要进行很多微调,但你可能能够实现更高的电子邮件吞吐量。

2
如果有人在寻找这个答案,它已经过时了,你可以在这里找到新的文档:https://docs.aws.amazon.com/aws-sdk-php/v3/guide/guide/commands.html。请注意保留HTML标签。
use Aws\S3\S3Client;
use Aws\CommandPool;

// Create the client.
$client = new S3Client([
    'region'  => 'us-standard',
    'version' => '2006-03-01'
]);

$bucket = 'example';
$commands = [
    $client->getCommand('HeadObject', ['Bucket' => $bucket, 'Key' => 'a']),
    $client->getCommand('HeadObject', ['Bucket' => $bucket, 'Key' => 'b']),
    $client->getCommand('HeadObject', ['Bucket' => $bucket, 'Key' => 'c'])
];

$pool = new CommandPool($client, $commands);

// Initiate the pool transfers
$promise = $pool->promise();

// Force the pool to complete synchronously
$promise->wait();

SES命令也可以执行同样的操作。


谢谢您发布这篇文章。我在这里使用了您的代码,它显著加快了我的项目进度。我正在使用AWS将电子邮件排队到SQS(队列),然后使用SES(简单电子邮件服务)发送。对于3500封电子邮件,SQS-> sendMessage需要57秒,SQS-> sendMessageBatch需要14秒,而SQS-> sendMessage + CommandPool只需要4秒。大幅改善! - RedDragonWebDesign

0

感谢您的回答。这是一个很好的起点。@Jeremy Lindblom

我的问题现在是我无法让错误处理正常工作。 catch()块运行良好,而且在其中

$successfulCommands

返回所有成功的响应状态码,但仅在发生错误时。例如,在沙盒模式下出现“未验证地址”。就像catch()应该工作一样。:)

try块内的$successfulCommands仅返回:

SplQueue Object
(
    [flags:SplDoublyLinkedList:private] => 1
    [dllist:SplDoublyLinkedList:private] => Array
    (
    )
)

我无法弄清楚如何从亚马逊获取真实的响应,包括状态码等。


1
execute() 方法基本上返回传入的任何可迭代数据结构,但是命令对象已更新以反映它们的执行。由于启用了 SqlQueue::IT_DELETE_MODE,它从 SqlQueue 中删除了命令(在这种情况下是可迭代的数据结构),导致它们不被返回。我已经编辑了原始代码示例以添加对 iterator_to_array() 的调用,这应该可以解决问题。现在应该像以前一样遍历队列,但将命令存储在数组中,由 execute 返回所有命令对象。 - Jeremy Lindblom
谢谢Jeremy!iterator_to_array()解决了问题,现在我可以在try块内获取来自亚马逊的响应了!你是我的男人! :) - Heiko K.

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接