为什么在使用 PHP SDK 调用时 Amazon SES 有一半失败?

Why does Amazon SES fail half the time when called using the PHP SDK?

我正在使用适用于 PHP 的 AWS 开发工具包(版本 3.52.33,PHP 版本 7.2.19)并尝试使用简单电子邮件服务 (SES) 发送电子邮件。我配置了SES,可以成功运行示例代码。为了让我的生活更轻松,我写了一个发送电子邮件的功能(send_email.php):

<?php

// Path to autoloader for AWS SDK
define('REQUIRED_FILE', "/path/to/vendor/autoload.php");

// Region:
define('REGION','us-west-2');

// Charset
define('CHARSET','UTF-8');

// Specify Sender
define('SENDER', 'sender@xxxx.com');

require REQUIRED_FILE;

use Aws\Ses\SesClient;
use Aws\Ses\Exception\SesException;


function send_email($htmlBody,$textBody,$subject,$recipient) {

        $access_key = 'accessKey';
        $secret_key = 'secretKey';

        $ret_array = array('success' => false,
                        'message' => 'No Email Sent'
                        );

        $client = SesClient::factory(array(
                'version' => 'latest',
                'region' => REGION,
                'credentials' => array(
                        'key' => $access_key,
                        'secret' => $secret_key
                )
        ));


        try {
                $result = $client->sendEmail([
                        'Destination' => [
                                'ToAddresses' => [
                                        $recipient,
                                ],
                        ],
                        'Message' => [
                                'Body' => [
                                        'Html' => [
                                                'Charset' => CHARSET,
                                                'Data' => $htmlBody,
                                        ],
                                        'Text' => [
                                                'Charset' => CHARSET,
                                                'Data' => $textBody,
                                        ],
                                ],
                                'Subject' => [
                                        'Charset' => CHARSET,
                                        'Data' => $subject,
                                ],
                        ],
                        'Source' => SENDER,
                ]);

                $messageId = $result->get('MessageId');
                $ret_array['success'] = true;
                $ret_array['message'] = $messageId;
                echo("Email sent! Message ID: $messageId" . "\n");
        } catch (SesException $error) {
                echo("The email was not sent. Error message: " . $error->getAwsErrorMessage() . "\n");
                $ret_array['message'] = $error->getAwsErrorMessage();
        }

        return $ret_array;
}

这在从终端中的简单测试脚本 (test.php) 调用时有效:

<?php
ini_set('display_errors','On');
error_reporting(E_ALL | E_STRICT);

require_once './send_email.php';

$email = 'test@email.com';
$htmlbody = 'test';
$txtbody = 'test';
$subject = 'test email';

$success = send_email($htmlbody,$txtbody,$subject,$email);

我得到如下输出:

[~]$ php test.php
Email sent! Message ID: 0101016c8d665369-027be596-f8da-4410-8f09-ff8d7f87181b-000000

太棒了。但是,我这样做是为了从网站(新用户注册、密码重置等)发送自动电子邮件,当我尝试在更大的脚本中使用 send_email 时,我获得了 ~%50 的成功率(使用固定电子邮件地址时)。要么它工作并且一切正常,要么它失败并且没有错误消息:

The email was not sent. Error message: 

我知道抛出了一个异常,因为我在 catch 语句中结束了,但我不知道如何获得有关错误原因的更多信息,因为没有与异常关联的消息。我已经尝试扩展我在 catch 块中寻找的内容:

<snip>
catch (SesException $error) {
                echo("The email was not sent. Error message: " . $error->getAwsErrorMessage() . "\n");
                $ret_array['message'] = $error->getAwsErrorMessage();
                $ret_array['errorCode'] = $error->getAwsErrorCode();
                $ret_array['type'] = $error->getAwsErrorType();
                $ret_array['response'] = $error->getResponse();
                $ret_array['statusCode'] = $error->getStatusCode();
                $ret_array['isConnectionError'] = $error->isConnectionError();
        }

但是当它失败时,除了 isConnectionError = false 之外,其他所有内容都是 NULL。有趣的是,它完全是随机的——我根本无法辨别出它何时有效以及何时失败的模式。

另一个可能相关的注意事项:如果我循环发送电子邮件以便新用户收到 10 封电子邮件,要么他们 all 成功,要么他们 all 失败。

那么,有没有人对可能出现的问题有任何建议,或者我可以采取其他步骤来帮助诊断为什么会发生这种情况?

对于以后 运行 遇到类似问题的任何人,我最终提出了两个解决方案:

最初,我放弃了对 AWS SDK 的希望,转而使用 PHPMailer 这避免了这个问题(尽管我相信以性能损失为代价)。

真正的问题(我现在相当确定)是我的 CLI 和网络服务器提供的 PHP 版本不匹配。 This 博客 post 让我开始思考这可能是个问题。通过更新网络服务器使用的 cURL 和 PHP 的版本,我解决了这个问题。