如何在PHP中强制使用From:标头(信封发件人)而不将其放入mail()?

Leo*_*lis 8 php apache email postfix-mta

我有一个开发Web服务器(CentOS LAMP堆栈),它使用postfix中的SMTP中继设置来发送电子邮件.我们使用带有多个用户的mailgun,类似于的设置,但是使用特定用户而不仅仅是通配符电子邮件:

/etc/postfix/main.cf中

smtp_sasl_password_maps = hash:/etc/postfix/sasl_passwd
smtp_sasl_auth_enable = yes
sender_dependent_relayhost_maps = hash:/etc/postfix/relayhost_map
smtp_sender_dependent_authentication = yes
smtp_sasl_security_options = noanonymous
relayhost = [smtp.mailgun.org]:587
Run Code Online (Sandbox Code Playgroud)

/等/后缀/ sasl_passwd

# our domains
no-reply@domain.com  postmaster@domain.com:password1
info@domain2.com     postmaster@domain2.com:password2
support@domain3.com  postmaster@domain3.com:password3

# in-case we don't have it setup, use a default
#[smtp.mailgun.org]:587      postmaster@domain2.com:password2
Run Code Online (Sandbox Code Playgroud)

/等/后缀/ relayhost_map

no-reply@domain.com  [smtp.mailgun.org]:587
info@domain2.com     [smtp.mailgun.org]:587
support@domain3.com  [smtp.mailgun.org]:587
Run Code Online (Sandbox Code Playgroud)

要设置电子邮件日志记录,我使用自己的SMTP凭据验证计算机上的每个开发人员.我想设置它,以便开发人员不需要在postfix中添加additional_headersadditional_parameters获取正确的smtp中继匹配 - 事实上,在代码中为不同的开发人员设置不同的邮件头需要做很多工作,特别是对于版本化的码.我离题了.当我使用以下内容时,这在postfix的方面工作得很好:

mail('email@address.tld', 'subject', 'message here...', 'From: noreply@domain.com', '-fnoreply@domain.com');
Run Code Online (Sandbox Code Playgroud)

所以我然后将以下内容添加到vhost配置中:

php_admin_value sendmail_path "/usr/sbin/sendmail -t -i -fnoreply@domain.com"
Run Code Online (Sandbox Code Playgroud)

这成功地让我摆脱了-f additional_parameter仍然正确发送.然后我添加了以下内容:

php_value sendmail_from "noreply@domain.com"
Run Code Online (Sandbox Code Playgroud)

phpinfo()转储中,我看到sendmail_from正确设置了本地值,但是现在当我发送电子邮件时,它显示为:

None@domain.com代表Apache

似乎正确的发件人(MIME,而不是信封,因为postfix识别身份验证并获得250次成功).使用详细的postfix登录,我只看到来自sender输入属性的正确电子邮件的引用.

在mailgun中,我看到日志中的以下信息,但是,对于From: noreply@domain.com 使用的电子邮件:

...
"envelope": {
    "transport": "smtp", 
    "sender": "noreply@domain.com", 
    "sending-ip": "x.x.x.x", 
    "targets": "email@address.tld"
}, 
"message": {
    "headers": {
        "to": "email@address.tld", 
        "message-id": "2014061111016.ABC1D23456E@domain.com", 
        "from": "noreply@domain.com (Apache)", 
        "subject": "Debug Test"
    }, 
    "attachments": [], 
    "recipients": [
        "email@address.tld"
    ], 
    "size": 654
},
...
Run Code Online (Sandbox Code Playgroud)

有趣的是相同的日志,当From: noreply@domain.com 目前,message->headers->from被correcetly设置为noreply@domain.com(Apache)增加.当然这意味着它是PHP的错误并且PHP没有sendmail_from正确使用该值?

所以考虑到所有这些,我得到的问题是如何在PHP中设置默认的MIME发送者(From头),除了在mail()函数中?我上面的方法/配置错过了什么,或者它是否完全不可能?我很乐意在盒子外面思考一下,因为我们想要这个功能,这将有助于节省时间.

Jas*_*wer 5

sendmail_from 被忽略

来自http://www.php.net/manual/en/mail.configuration.php

sendmail_from string
Windows 下从 PHP 发送的邮件应使用哪个“发件人:”邮件地址。该指令还设置“Return-Path:”标头。

因此,由于您使用的是 CentOS LAMP 堆栈,而不是 Windows,因此会忽略此设置。

还:

sendmail_path string
如果设置,则忽略smtp、和 并执行指定的命令。smtp_portsendmail_from

Sosendmail_from也被忽略,因为您正在使用sendmail_path.

解决方案

您还可以传递-F带有空值的(大写 F),以从标头中删除“发件人全名”:

传递-f noreply@domain.com -F ""给函数$additional_parameters的参数mail()

其他注意事项

-f参数

当您看到发件人地址发生更改时,Postfix 就会执行此操作。这是因为(在您的情况下)Apache 运行所在的系统用户正在调用sendmail二进制文件。这个二进制文件将用作<system-user>@<hostname>发送者地址(除非-for-r参数另有说明)。

为了防止这种情况,sendmail应该用 来调用-f <sender address>。通过将其传递给函数$additional_parameters的参数mail(),或者将其添加到sendmail_pathini 设置中。

但看起来你已经明白了这一点:)

更好的解决方案

我建议您根本不要使用 ini 设置。相反,围绕该mail()函数编写一个小类:

class Mailer
{
    /**
     * @var string
     */
    private $fromEmail;

    /**
     * @var string
     */
    private $fromName;

    /**
     * @param string $fromEmail
     * @param string $fromName
     */
    public function __construct($fromEmail, $fromName)
    {
        $this->fromEmail = $fromEmail;
        $this->fromName  = $fromName;
    }

    /**
     * @param  string $to
     * @param  string $subject
     * @param  string $body
     * @param  array  $headers
     * @return bool
     */
    public function send($to, $subject, $body, array $headers = array())
    {
        $headers[]  = sprintf('From: "%s" <%s>', $this->fromName, $this->fromEmail);
        $parameters = sprintf('-f %s', $this->fromEmail);

        return mail($to, $subject, $body, $headers, $parameters);
    }
}
Run Code Online (Sandbox Code Playgroud)

并像这样使用它:

$mailer = new Mailer('noreply@domain.com', 'My Company');
$mailer->send('email@address.tld', 'Subject', 'Body');
Run Code Online (Sandbox Code Playgroud)

此类过于简单,但它应该让您了解如何在每次发送电子邮件时消除From:标头和参数的麻烦。-f

如果您使用依赖注入容器或注册表,您可以在应用程序的引导阶段配置/实例化此类,并在您想要发送电子邮件时只需从容器/注册表中获取它:

$container->get('mailer')->send($to, $subject, $message);
Run Code Online (Sandbox Code Playgroud)

或者使用注册表:

Registry::get('mailer')->send($to, $subject, $message);
Run Code Online (Sandbox Code Playgroud)

第三方库

从长远来看,研究第三方库来发送电子邮件可能是值得的。我个人更喜欢Swift Mailer