我正在尝试通过 SMTP 进行批量发送,但即使我发送给多个收件人并且已指定用户变量(并且变量在发送的电子邮件中成功替换),每个收件人都会显示在接收方生成的消息的“收件人:”字段中。
根据 MailGun 关于 批量发送...
的文档警告: 使用批量发送时同时使用收件人变量非常重要。这告诉 Mailgun 向每个收件人发送一封单独的电子邮件,并且“收件人”字段中仅包含他们的电子邮件。如果不使用它们,所有收件人的电子邮件地址将显示在每个收件人的“收件人”字段中。
这是我的 SMTP 标头示例...
To: [email protected], [email protected]
X-Mailgun-Recipient-Variables: {
"[email protected]":
{
"id":"12345",
"email":"[email protected]",
"first_name":"Foo"
},
"[email protected]":
{
"id":"45678",
"email":"[email protected]",
"first_name":"Bar"
}
}
生成的电子邮件在“收件人”字段中应仅显示每封电子邮件的一个收件人。 我是不是错过了什么?
我昨天开始搞乱这个问题,我想我已经找到了解决方案。
诀窍是将“收件人:”地址留空,并将收件人添加到“密件抄送”行。 接下来,添加自定义标头 - 收件人:%recipient%。 $mail->send() 不会抱怨,收到的电子邮件中的“收件人:”字段仅显示单个收件人的电子邮件。
代码示例:
$mail = new PHPMailer();
$mail->isSMTP();
$mail->Host = 'smtp.host';
$mail->SMTPAuth = true;
$mail->Username = 'yourUserName';
$mail->Password = 'yourPassword';
$mail->SMTPSecure = 'tls';
$mail->From = '[email protected]';
$mail->FromName = 'John Doe';
$mail->addBCC('[email protected]');
$mail->addBCC('[email protected]');
$headerLine = $mail->headerLine('X-Mailgun-Recipient-Variables', '{"[email protected]": {"first":"FooBar1", "id":1}, "[email protected]": {"first":"FooBar2", "id": 2}}');
$mail->addCustomHeader($headerLine);
$headerLine = $mail->headerLine('To','%recipient%');
$mail->addCustomHeader($headerLine);
$mail->Subject = 'Hello, %recipient.first%!';
$mail->Body = 'Hello %recipient.first%, Your ID is %recipient.id%.';
if(!$mail->send())
{
echo 'Message could not be sent.';
echo 'Mailer Error: ' . $mail->ErrorInfo;
}
else
{
echo 'Message has been sent';
}
我也没有成功地让它发挥作用。 我放入了一张邮枪故障单。 以下是他们回应的实质:
我们文档中的“警告”实际上仅针对 API,而不针对 SMTP。原因是,当使用 API 时,我们形成/创建电子邮件,这允许我们的服务在“收件人:”字段中为每个收件人单独创建一封新电子邮件。不过,当使用 SMTP 时,我们只是中继带有提交到我们服务的内容的消息,我们实际上并没有从头开始创建消息 MIME。
要解决此问题,您可以在“收件人:”字段中输入 %recipient%。这将为在与我们的服务器进行 SMTP 会话期间“RCPT TO”中指定的每个地址创建单独的消息。现在,事情变得有点棘手,因为我对 ASP SMTP 连接器的不熟悉从这里开始显现出来。在我的研究中,我还没有找到使用 ASP SMTP 连接器指定 RCPT TO 的方法。它似乎依赖于您在“收件人”中输入的内容,并且没有提供指定“收件人:”字段和“RCPT TO:”字段的方法。
当我尝试使用 %recipient% 作为 TO 变量时,其内置方法会引发错误,
"CDO.Message.1 error '8004020c' At least one recipient is required, but none were found."
我对其他邮件程序不熟悉,但如果有任何邮件程序允许这种构造,我会感到惊讶。
对 WordPress 网站有相同的要求,这里是我为需要它的人提供的东西:
class PHPMailerForMailgunBatch extends PHPMailer {
public function createHeader() {
$header = parent::createHeader();
$header = preg_replace( "/To: .*\n/", "To: %recipient%\n", $header );
return $header;
}
}
然后
global $phpmailer;
$phpmailer = new PHPMailerForMailgunBatch( true );
// Config mailgun SMTP here
$mailgunBatchHeader = "X-Mailgun-Recipient-Variables: " . json_encode( $yourMailgunBatchVariables );
wp_mail( $emails, $subject, $content, [
$mailgunBatchHeader
] );
扩展“MailgunHttpTransport”或 smpt one 驱动程序并覆盖发送数据和标头。
示例:
protected function doSendHttp(SentMessage $message): ResponseInterface
{
$addresses = $this->stringifyAddresses($message->getEnvelope()->getRecipients());
if (count($addresses) <= 1) {
return parent::doSendHttp($message);
}
$toValues = str($message->toString())->betweenFirst('To: ', "\r\n");
$messageString = str($message->toString())->replaceFirst($toValues, "%recipient%")->toString();
$body = new FormDataPart([
'to' => implode(',', $addresses),
'message' => new DataPart($messageString, 'message.mime'),
'recipient-variables' => collect($addresses)->mapWithKeys(fn($add) => [$add => (object)[]])->toJson()
]);
$headers = [];
foreach ($body->getPreparedHeaders()->all() as $header) {
$headers[] = $header->toString();
}
$endpoint = sprintf('%s/v3/%s/messages.mime', $this->getEndpoint(), urlencode($this->domain));
$response = $this->client->request('POST', 'https://' . $endpoint, [
'auth_basic' => 'api:' . $this->key,
'headers' => $headers,
'body' => $body->bodyToIterable(),
]);
try {
$statusCode = $response->getStatusCode();
$result = $response->toArray(false);
} catch (DecodingExceptionInterface) {
throw new HttpTransportException('Unable to send an email: ' . $response->getContent(false) . sprintf(' (code %d).', $statusCode), $response);
} catch (TransportExceptionInterface $e) {
throw new HttpTransportException('Could not reach the remote Mailgun server.', $response, 0, $e);
}
if (200 !== $statusCode) {
throw new HttpTransportException('Unable to send an email: ' . $result['message'] . sprintf(' (code %d).', $statusCode), $response);
}
$message->setMessageId($result['id']);
return $response;
}