【问题标题】:PHP Sending Large Amounts of Email to Amazon SESPHP 向 Amazon SES 发送大量电子邮件
【发布时间】:2013-09-30 07:27:45
【问题描述】:

我有一个向 Amazon SES 发送电子邮件的在线软件。目前我有一个 cron 作业,通过 SMTP 发送电子邮件,使用 phpmailer 发送消息。目前,我必须将发送限制设置为每分钟大约 300 次,以确保我的服务器不会超时。我们看到了增长,最终我想发送到 10,000 或更多。

有没有更好的方法发送到 Amazon SES,或者其他人都这样做,但只有更多的服务器运行工作负载?

提前致谢!

【问题讨论】:

    标签: php amazon-web-services phpmailer amazon-ses


    【解决方案1】:

    您可以尝试使用适用于 PHP 的 AWS 开发工具包。您可以通过 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 and friends 使其更加健壮。

    您需要对这段代码进行微调,但您也许能够实现更高的电子邮件吞吐量。

    【讨论】:

      【解决方案2】:

      如果有人在寻找这个答案,它已经过时了,你可以在这里找到新的文档:https://docs.aws.amazon.com/aws-sdk-php/v3/guide/guide/commands.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 需要 57s,SQS->sendMessageBatch 需要 14s,SQS->sendMessage + CommandPool 需要 4s。大进步!
      【解决方案3】:

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

      我现在的问题是我无法让错误处理工作。 catch()-Block 工作正常,在里面

      $successfulCommands
      

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

      try-Block 内的 $successfulCommands 只返回:

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

      我无法弄清楚如何使用状态代码等从亚马逊获得真正的响应。

      【讨论】:

      • execute() 方法基本上返回传入的任何可迭代数据结构,但命令对象会更新以反映其执行情况。由于启用了SqlQueue::IT_DELETE_MODE,它从SqlQueue(在这种情况下是可迭代的数据结构)中删除了命令,导致它们不会被返回。我已经编辑了我的原始代码示例以添加对 iterator_to_array() 的调用,这应该可以修复它。它现在应该像以前一样遍历队列,但将命令存储在一个数组中,execute 将返回该数组,其中包含所有命令对象。
      • 谢谢杰里米! iterator_to_array() 可以解决问题,现在我可以在 try-Block 中获得来自亚马逊的响应!你是我的男人! :)
      猜你喜欢
      • 1970-01-01
      • 2012-06-22
      • 2016-08-22
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2020-04-20
      相关资源
      最近更新 更多