PHP mail()失败主因是PHP进程用户权限不足:/usr/sbin/sendmail需可执行,sendmail_path路径须正确且可访问,系统临时目录(如/tmp)需可写,SELinux/AppArmor策略可能拦截,须用实际运行用户模拟测试验证。
PHP 修改文件或目录权限本身不会直接影响 mail() 函数能否发邮件,但权限设置不当可能间接导致邮件发送失败——关键在于 PHP 进程能否访问邮件相关资源(如 sendmail 二进制、临时目录、配置文件)。
排查重点不是 PHP 脚本自身的读写权限,而是 PHP 运行用户(如 www-data、apache 或 nginx)是否具备调用系统邮件代理的权限:
/usr/sbin/sendmail(或 /usr/bin/sendmail)必须对 PHP 进程用户可执行;若被设为 700 且属主非 PHP 用户,则调用失败sendmail_path 配置指向的路径必须存在且可执行;常见错误是路径写错,或符号链接断裂(ls -l /usr/sbin/sendmail 看是否指向真实二进制)sys_temp_dir(或系统默认临时目录如 /tmp)需对 PHP 用户可写;否则邮件头解析、附件临时存储会失败,报错类似 failed to open stream: Permission denied
ini_set('sendmail_path', ...) 动态覆盖路径,该字符串里的命令及其依赖(如 -t 参数需要的 stdin 处理)也受权限约束别只看 mail() 返回 true,它只表示“提交成功”,不保证实际投递。直接模拟 PHP 调用方式测试:
sudo -u www-data /usr/sbin/sendmail -t <<'EOF' To: test@example.com Subject: CLI Test This is a test. EOF
如果报 Permission denied 或 No such file or directory,说明权限或路径有问题。注意:sudo -u 必须用 PHP 实际运行的用户,不是 root 或当前登录用户。
command not found:检查 sendmail_path 配置值是否与 which sendmail 输出一致cannot execute binary file:可能是架构不匹配(如 ARM 服务器装了 x86 sendmail),或 SELinux/AppArmor 拦截(见下一条)/var/log/mail.log 或 journalctl -u postfix,确认 MTA 是否收到请求在 CentOS/RHEL(SELinux)或 Ubuntu(AppArmor)上,即使文件权限全开,安全模块仍可能阻止 Apache/Nginx 进程执行

mail() 返回 false,日志里没有 sendmail 调用记录,audit.log 中出现 avc: denied。
setenforce 0(SELinux)或 aa-disable /etc/apparmor.d/usr.sbin.apache2(Ubuntu),再试 mail();若恢复则确认是策略拦截ausearch -m avc -ts recent | audit2why 分析,然后用 audit2allow 生成新规则httpd_can_sendmail 是否为 on(getsebool httpd_can_sendmail)真正卡住人的往往不是 sendmail 权限本身,而是 PHP 进程用户和 MTA 用户之间的信任链断在哪一环——比如 Postfix 配置了 smtpd_relay_restrictions 拒绝本地未认证提交,或 Docker 容器里没挂载 /usr/sbin/sendmail。先确认 PHP 能否以对应用户身份手动跑通 sendmail,再查代码逻辑,比盲目改 chmod 777 有效得多。