如何使用PHP邮件更改信封发件人地址?

38
我正在Linux上使用Apache和Sendmail,使用PHP的mail函数发送电子邮件。邮件已经发送,但信封中的MAIL FROM(例如nobody@conniptin.internal)是Apache_user@localhostname,因此一些远程邮件服务器会拒绝它,因为该域不存在(显然)。在使用mail时,我能否强制更改信封中的MAIL FROM
编辑:如果我在mail()函数的第四个字段中添加一个标头,则会更改消息正文中标头的From字段,但不会更改信封中的MAIL FROM
我可以通过生成带有sendmail -t -odb -oi -frealname@realhost的sendmail并将电子邮件内容传输到其中来强制执行此操作。这是更好的方法吗?
是否有更好、更简单、更适合PHP的方法?
编辑:最重要的是我应该阅读手册。感谢大家的答案,第五个参数有效,一切都很好。
6个回答

78

mail()有第四和第五个参数(可选)。第五个参数是应直接作为选项传递给sendmail的内容。我使用以下内容:

mail('to@blah.com','subject!','body!','From: from@blah.com','-f from@blah.com');

2
注意:您可能还需要将发件人添加到 /etc/mail/trusted-users 中。 - Devon
我的机器上找不到 trusted-users:/ - Doug Molineux
10
@Lucas Oman:+1 你的回答是正确的,我想警告任何可能感兴趣的人,几乎所有共享主机服务(cPanel/WHM)都禁用了PHP邮件函数第五个参数“-f ...”,原因是“SAFE MODE限制生效”,只会显示一个PHP警告,而不改变默认的信封发件人,因此在这些情况下,你的答案将不是一个选项。关于Devon的评论,由于属于主服务器配置,因此在共享主机上无法更改“/etc/mail/trusted-users”。 - Marco Demaio
2
在我上一条评论中,safe_mode 已经自 PHP 5.3.0 起被弃用 [参考 http://php.net/manual/en/features.safe-mode.php]。因此,如果您的共享主机服务仍然使用它,您可以向其技术支持提出投诉。当 PHP 的 safe_modeOff 时,Lucas Oman 的答案完美适用。 - Marco Demaio
这在Windows上不起作用(通过SMTP发送)。只有使用sendmail时才能正常工作。对于Windows,您需要修改PHP配置或调用ini_set('sendmail_from','yourmail@example.com'); - Simon East

2

PHP mail() 函数官方文档

bool mail ( string $to , string $subject , string $message [, string $additional_headers [, string $additional_parameters ]] )

...

additional_parameters(可选)

additional_parameters 参数可以用来将额外的标志作为命令行选项传递给配置为用于发送邮件的程序, 该程序由 sendmail_path 配置设置定义。例如,当使用 sendmail 和 -f sendmail 选项时,这可以用于设置信封发件人地址。

此参数在内部通过 escapeshellcmd() 进行转义以防止命令执行。 escapeshellcmd() 可以防止命令执行,但允许添加其他参数。出于安全原因,建议用户对此参数进行清理以避免向 shell 命令中添加不需要的参数。

由于 escapeshellcmd() 自动应用,因此一些按照互联网 RFC 允许用作电子邮件地址的字符不能使用。 mail() 无法允许使用这样的字符,因此在需要使用这样的字符的程序中,建议使用其他发送电子邮件的方式(例如使用框架或库)。

Web 服务器运行的用户应将其添加为信任用户,以防止使用此方法设置信封发件人(-f)时向消息添加“X-Warning”头。对于 sendmail 用户,此文件是 /etc/mail/trusted-users


在类UNIX环境之外的共享主机上,您有什么想法可以找到类似于/etc/mail/trusted-users的等效文件? - oldboy

1
你可以尝试这个(我不太确定):
ini_set("sendmail_from", yourmail@example.com);
mail(...);
ini_restore("sendmail_from");

好主意,我在共享主机上尝试过这个方法,但不幸的是这不是一个解决方法,因为当safe_mode=On时,甚至ini_set("sendmail_from"也会被忽略。而当safe_mode=Off时,Lucas Oman的答案更简单、更快速[https://dev59.com/33VC5IYBdhLWcg3wz0h9#179061]。 - Marco Demaio
1
这只适用于Windows服务器(如PHP.ini中所述),但是非常好的提示。 - Simon East

1
我也建议查看PHPMailer。它非常适合创建和发送电子邮件,使整个过程更加简单,并支持SMTP。

PHPMailer似乎正如Lucas Oman在上面的答案中建议的那样,确切地使用了PHP邮件第5个参数-f ...。您可以在PHPMailer源文件class.phpmailer.php中的function MailSend 中看到它。 - Marco Demaio

0

无论哪种方式对我来说都没有任何区别。 - Chris Barr

-10

您需要做的是更改运行 Apache 的机器的主机名以及Apache正在运行的用户

在您当前的情况下,它是:

  • Apache用户:nobody
  • 服务器主机名:conniptin.internal

更改这两个值非常简单,可以解决您问题的根源。

虽然如果您需要从PHP中执行该操作,则可以使用system/exec函数。但我认为它在实践中可能无法正常工作,因为您需要重新启动Apache,还有可能需要重启整个主机才能使用新名称。


更改主机名和以不同的用户身份运行Apache会产生深远的后果(在后一种情况下可能会带来严重的安全后果),通常不被组织政策或共享托管提供商所允许。 - qris
好的,这确实解决了我的问题(在一些谷歌搜索之后)...但我在一个VPS上。 - Roemer

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接