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

时间:2014-06-12 11:19:15

标签: php apache email postfix-mta

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

/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

/等/后缀/ 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

/等/后缀/ relayhost_map

no-reply@domain.com  [smtp.mailgun.org]:587
info@domain2.com     [smtp.mailgun.org]:587
support@domain3.com  [smtp.mailgun.org]:587

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

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

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

php_admin_value sendmail_path "/usr/sbin/sendmail -t -i -fnoreply@domain.com"

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

php_value sendmail_from "noreply@domain.com"

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
},
...

有趣的是,From: noreply@domain.com 出现时的相同日志,message->headers->from在没有{{1}的情况下正确设置为noreply@domain.com另外。当然这意味着PHP的错误并且PHP没有正确使用(Apache)值?

考虑到所有这些,我得到的问题是如何在PHP中设置默认的MIME发件人(From标头),除了sendmail_from功能?我错过了吗?我的方法/配置上面的东西,或者它只是简单的不可能?我很乐意在盒子外面思考一下,因为我们想要这个功能,这将有助于节省时间。

2 个答案:

答案 0 :(得分:4)

忽略

sendmail_from

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

  

sendmail_from string
  哪个"来自:"邮件地址应该用在Windows下从PHP发送的邮件中。   该指令还设置了" Return-Path:"报头中。

因为您使用的是CentOS LAMP堆栈,不是Windows ,所以会忽略此设置。

此外:

  

sendmail_path string
  如果设置,则忽略smtpsmtp_portsendmail_from并执行指定的命令。

因为您正在使用sendmail_from,所以sendmail_path也会被忽略。

解决方案

您还可以使用空值传递-F(大写字母F),以删除"发件人全名"从标题:

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

其他说明

-f参数

当您看到发件人地址发生变化时,Postfix就是这样做的。这是因为(在您的情况下)Apache运行的系统用户正在调用sendmail二进制文件。此二进制文件将使用<system-user>@<hostname>作为发件人地址(除非-f-r参数另有说明。)

为防止出现这种情况,应使用sendmail调用-f <sender address>。将其传递到$additional_parameters函数的mail()参数,或将其添加到sendmail_path ini-setting中。

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

更好的解决方案

我建议你根本不使用ini-settings。相反,在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);
    }
}

并像这样使用它:

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

这个类过于简化,但它应该让您基本了解每次发送电子邮件时如何否定From:标题和-f参数的麻烦。

如果您正在使用依赖注入容器或注册表,则可以在应用程序的引导阶段配置/实例化此类,只需在发送e时从容器/注册表中获取它-mail:

$container->get('mailer')->send($to, $subject, $message);

或使用注册表:

Registry::get('mailer')->send($to, $subject, $message);

第三方图书馆

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

答案 1 :(得分:0)

请务必使用正确的smtp sasl贴图设置后缀。通常在/etc/postfix/main.cf

找到

查找或添加:

# SASL
smtp_sasl_password_maps = static:noreply@domain.com:xxxxx 

电子邮件是配置的SMTP电子邮件,xxxxx是您在mailgun中配置的SMTP密码。

重新启动您的服务(包括postfix),您应该开始营业。