使用收件人变量的 MailGun SMTP 批量发送在“收件人”字段中显示所有收件人

问题描述 投票:0回答:4

我正在尝试通过 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"
    }
}

生成的电子邮件在“收件人”字段中应仅显示每封电子邮件的一个收件人。 我是不是错过了什么?

php email smtp mailgun
4个回答
6
投票

我昨天开始搞乱这个问题,我想我已经找到了解决方案。

诀窍是将“收件人:”地址留空,并将收件人添加到“密件抄送”行。 接下来,添加自定义标头 - 收件人:%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';
}

2
投票

我也没有成功地让它发挥作用。 我放入了一张邮枪故障单。 以下是他们回应的实质:

我们文档中的“警告”实际上仅针对 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."
我对其他邮件程序不熟悉,但如果有任何邮件程序允许这种构造,我会感到惊讶。


0
投票

对 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 
] ); 

0
投票

扩展“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;
}
© www.soinside.com 2019 - 2024. All rights reserved.