Perl CGI脚本发邮件后出现500错误及输出提前结束问题求助
解决Perl CGI脚本发送邮件后出现500 Internal Server Error的问题
问题现象
邮件可正常发送,但脚本执行后返回500 Internal Server Error,服务器日志提示:
[Tue Jan 17 16:00:23.475272 2023] [cgi:error] [pid 230679] [client 69.90.223.10:35014] End of script output before headers: test3.cgi
已确认CGI文件权限为755,脚本可执行到发送邮件的子程序,但仍触发错误。
核心原因
CGI规范强制要求脚本必须先向Web服务器输出HTTP响应头(至少包含Content-Type字段),再输出响应内容。当前脚本仅执行邮件发送逻辑后直接exit,未输出任何HTTP头,服务器无法识别有效响应,因此返回500错误。
另外,脚本中使用的die语句如果触发(比如SMTP连接失败),会直接输出错误信息到标准输出,但同样没有前置HTTP头,也会导致相同的错误。
解决方案
修改后的完整代码
#!/usr/bin/perl -Tw use warnings; # 取消注释,便于排查潜在问题 use strict; use Net::SMTP; # 先输出HTTP响应头,这是CGI脚本的强制要求 print "Content-Type: text/plain\n\n"; eval { send_mail( 'mail.xxxxxxx.com', # Host 'order@xxxxxxxxx.com', # From 'yyyyyyy@gmail.com', # To 'Just a test, from mail.xxxxxx.com please ignore', # Message body "Testing mail server email.\n" # Subject ); print "邮件发送成功\n"; }; if ($@) { print "邮件发送失败: $@"; } exit; sub send_mail { my ($SMTP_HOST, $from, $to_addr, $body, $subject, $msg) = @_; $msg = "MIME-Version: 1.0\n" . "From: $from\n" . "To: " . ( ref($to_addr) ? join(';', @$to_addr) : $to_addr ) . "\n" . "Subject: $subject\n\n" # 双换行分隔邮件头和正文 . $body; my $smtp = Net::SMTP->new( $SMTP_HOST, Debug => 0, # 改为1可开启SMTP调试信息 Port => 587, ); die("SMTP ERROR: Unable to open smtp session.\n") if(!defined($smtp) || !($smtp)); die("Failed to set FROM address\n") if (! ($smtp->mail( $from ) ) ); die("Failed to set recipient\n") # 修正拼写错误receipient -> recipient if (! ($smtp->recipient( ( ref($to_addr) ? @$to_addr : $to_addr ) ) ) ); $smtp->data( $msg ); $smtp->quit; }
关键修改说明
- 添加HTTP响应头:脚本开头先输出
Content-Type: text/plain\n\n,满足CGI规范要求 - 异常捕获:用
eval包裹邮件发送逻辑,捕获die抛出的异常,统一输出带HTTP头的错误信息 - 启用警告:取消
use warnings;的注释,便于发现脚本中的语法或逻辑隐患 - 拼写修正:修复
send_mail子程序中的拼写错误receipient改为recipient
额外排查方向
- 命令行直接执行脚本:
./test3.cgi,查看输出是否包含HTTP头和预期内容,排查脚本本身的执行错误 - 验证模块依赖:执行
perl -MNet::SMTP -e 1,无报错则表示Net::SMTP模块已正确安装 - 查看系统日志:检查
/var/log/messages等系统日志,确认是否有Perl执行相关的权限或路径错误
内容的提问来源于stack exchange,提问作者Michael
相关产品推荐
相关产品推荐

