Skip to content

Perl 发送电子邮件

从 Perl 脚本发送电子邮件是通知、报告或应用程序警报的常见任务。现代 Perl 在 CPAN 上提供了几个模块,用于强大而灵活的电子邮件处理。虽然在类 Unix 系统上直接使用像 sendmail 这样的系统工具是可能的,但通常更推荐使用模块,以提高可移植性、功能和易用性。

使用系统 sendmail 工具(Unix/Linux)

Section titled “使用系统 sendmail 工具(Unix/Linux)”

在配置了 sendmail(或兼容的邮件传输代理 MTA,如 Postfix 或 Exim)的类 Unix 系统上,你可以将电子邮件内容通过管道发送给它。这种方法对于基本电子邮件来说很简单,但缺乏高级功能和可移植性。

#!/usr/bin/perl
use strict;
use warnings;
my $to = 'recipient@example.com';
my $from = 'sender@example.com';
my $subject = 'Test Email from Perl (sendmail)';
my $message_body = "This is a test email sent by a Perl script using sendmail.
Regards,
Perl Script";
# Adjust path to sendmail if necessary
# 如有必要,调整 sendmail 的路径
my $sendmail_path = "/usr/sbin/sendmail";
unless (open(MAIL, "|- ", "$sendmail_path -t -oi")) {
die "Could not open pipe to sendmail: $!";
# 无法打开到 sendmail 的管道:$!
}
print MAIL "To: $to\n";
print MAIL "From: $from\n";
print MAIL "Subject: $subject\n";
print MAIL "\n"; # Blank line separates headers from body
# 空行将头部与正文分开
print MAIL $message_body;
unless (close(MAIL)) {
die "Sendmail command failed: $? $!"; # $? for exit status
# sendmail 命令失败:$? $! # $? 表示退出状态
}
print "Email sent successfully via sendmail (hopefully!)\n";
# 通过 sendmail 成功发送电子邮件(希望如此!)

注意:-t 选项告诉 sendmail 从头部读取收件人。-oi 防止将只有单个点的行视为消息结束。此方法依赖于正确配置的本地 MTA。

使用 Perl 模块发送电子邮件(推荐)

Section titled “使用 Perl 模块发送电子邮件(推荐)”

使用 CPAN 模块是 Perl 中处理电子邮件的标准和推荐方式。像 Email::Stuffer、Email::Sender 和较旧的 MIME::Lite 等模块提供了全面的功能。

要安装模块,通常使用 cpanm(App::cpanminus):

cpanm Module::Name # e.g., cpanm Email::Stuffer
# 例如,cpanm Email::Stuffer

使用 MIME::Lite 模块(较旧,但仍然可用)

Section titled “使用 MIME::Lite 模块(较旧,但仍然可用)”

MIME::Lite 是一个历史悠久的模块,用于创建和发送 MIME 消息。虽然较新的模块提供了更现代的 API,但对于基本任务来说,MIME::Lite 相对简单。对于新项目,可以考虑使用 Email::Stuffer 或将 Email::Sender 与 Email::MIME::Creator 结合使用。

使用 MIME::Lite 发送纯文本消息:

#!/usr/bin/perl
use strict;
use warnings;
use MIME::Lite;
my $to = 'recipient@example.com';
my $from = 'sender@example.com';
my $subject = 'Test Email from Perl (MIME::Lite)';
my $message_body = "This is a test email sent via MIME::Lite.";
# 这是通过 MIME::Lite 发送的测试电子邮件。
try {
my $msg = MIME::Lite->new(
From => $from,
To => $to,
Subject => $subject,
Data => $message_body,
Type => 'text/plain' # Explicitly set type
# 明确设置类型
);
# By default, MIME::Lite tries to use sendmail.
# 默认情况下,MIME::Lite 尝试使用 sendmail。
# For other transport methods, see send_by_smtp below.
# 对于其他传输方法,请参阅下面的 send_by_smtp。
$msg->send;
print "Email sent successfully via MIME::Lite!\n";
# 通过 MIME::Lite 成功发送电子邮件!
}
catch {
warn "Failed to send email: $_\n";
# 发送电子邮件失败:$_\n
};

使用 MIME::Lite 发送 HTML 消息:

#!/usr/bin/perl
use strict;
use warnings;
use MIME::Lite;
my $to = 'recipient@example.com';
my $from = 'sender@example.com';
my $subject = 'HTML Test Email from Perl (MIME::Lite)';
my $html_body = <<'END_HTML';
<h1>Hello from Perl!</h1>
<p>This is an **HTML** email sent using <code>MIME::Lite</code>.</p>
<p><a href="https://www.perl.org">Visit Perl.org</a></p>
END_HTML
try {
my $msg = MIME::Lite->new(
From => $from,
To => $to,
Subject => $subject,
Type => 'text/html', # Set content type to HTML
# 设置内容类型为 HTML
Data => $html_body
);
$msg->send;
print "HTML Email sent successfully via MIME::Lite!\n";
# 通过 MIME::Lite 成功发送 HTML 电子邮件!
}
catch {
warn "Failed to send HTML email: $_\n";
# 发送 HTML 电子邮件失败:$_\n
};

使用 MIME::Lite 发送带附件的电子邮件:

#!/usr/bin/perl
use strict;
use warnings;
use MIME::Lite;
my $to = 'recipient@example.com';
my $from = 'sender@example.com';
my $subject = 'Email with Attachment (MIME::Lite)';
my $text_body = "Please find the attached report.";
# 请查收附件报告。
my $attachment_path = './report.txt'; # Create a dummy report.txt for testing
# 为测试创建一个虚拟的 report.txt 文件
# Create a dummy attachment file for testing
# 为测试创建虚拟附件文件
open my $fh, '>', $attachment_path or die "Cannot create dummy attachment: $!";
# 无法创建虚拟附件:$!
print $fh "This is a test report.\nLine 2 of report.\n";
# 这是测试报告。
# 报告的第 2 行。
close $fh;
try {
my $msg = MIME::Lite->new(
From => $from,
To => $to,
Subject => $subject,
Type => 'multipart/mixed' # For messages with attachments
# 用于带附件的消息
);
# Attach the text part
# 附加文本部分
$msg->attach(
Type => 'text/plain',
Data => $text_body
);
# Attach the file
# 附加文件
$msg->attach(
Type => 'text/plain', # Or application/octet-stream, etc.
# 或 application/octet-stream 等
Path => $attachment_path,
Filename => 'report_from_perl.txt', # Name for the attachment
# 附件名称
Disposition => 'attachment'
);
$msg->send;
print "Email with attachment sent successfully via MIME::Lite!\n";
# 通过 MIME::Lite 成功发送带附件的电子邮件!
}
catch {
warn "Failed to send email with attachment: $_\n";
# 发送带附件的电子邮件失败:$_\n
}
unlink $attachment_path; # Clean up dummy file
# 清理虚拟文件

如果你的机器未配置为直接发送邮件(例如,没有本地 sendmail),或者你需要使用特定的 SMTP 服务器(如 Gmail, SendGrid 等),你可以配置 MIME::Lite 通过 SMTP 发送。这通常需要安装 Net::SMTP。

#!/usr/bin/perl
use strict;
use warnings;
use MIME::Lite;
my $to = 'recipient@example.com';
my $from = 'sender@example.com'; # Often needs to be a valid address on the SMTP server
# 通常需要在 SMTP 服务器上是有效的地址
my $subject = 'SMTP Test from MIME::Lite';
# 来自 MIME::Lite 的 SMTP 测试
my $body = 'This email was sent via an external SMTP server.';
# 这封电子邮件是通过外部 SMTP 服务器发送的。
my $smtp_server = 'smtp.example.com';
my $smtp_user = 'your_username'; # Optional, if authentication is needed
# 可选,如果需要认证
my $smtp_pass = 'your_password'; # Optional
# 可选
try {
my $msg = MIME::Lite->new(
From => $from,
To => $to,
Subject => $subject,
Data => $body,
Type => 'text/plain'
);
# Option 1: Set global send method for MIME::Lite
# 选项 1:设置 MIME::Lite 的全局发送方法
# MIME::Lite->send('smtp', $smtp_server, AuthUser => $smtp_user, AuthPass => $smtp_pass, Debug => 1);
# $msg->send();
# Option 2: Use send_by_smtp (or send_via_smtp) on the message object
# 选项 2:在消息对象上使用 send_by_smtp(或 send_via_smtp)
# This requires Net::SMTP or similar to be available.
# 这需要 Net::SMTP 或类似模块可用。
$msg->send_by_smtp($smtp_server,
AuthUser => $smtp_user,
AuthPass => $smtp_pass,
Port => 587, # Common port for SMTP with STARTTLS
# SMTP STARTTLS 的常用端口
Hello => 'my.hostname.com', # Optional HELO/EHLO domain
# 可选的 HELO/EHLO 域名
# SSL => 'starttls', # For STARTTLS, often requires Net::SMTP::TLS::ButMaintained or IO::Socket::SSL
# 对于 STARTTLS,通常需要 Net::SMTP::TLS::ButMaintained 或 IO::Socket::SSL
# SSL => 1, # For SMTPS (SMTP over SSL directly on port 465)
# 对于 SMTPS(端口 465 上直接使用 SSL 的 SMTP)
Debug => 1 # Enable debugging output from Net::SMTP
# 启用 Net::SMTP 的调试输出
) or die "SMTP sending failed: " . MIME::Lite->errmsg;
# SMTP 发送失败:... # MIME::Lite->errmsg
print "Email sent successfully via SMTP!\n";
# 通过 SMTP 成功发送电子邮件!
}
catch {
warn "Failed to send email via SMTP: $_\n";
# 通过 SMTP 发送电子邮件失败:$_\n
if (MIME::Lite->errmsg) {
warn "MIME::Lite error: " . MIME::Lite->errmsg . "\n";
# MIME::Lite 错误:... # MIME::Lite->errmsg
}
};

对于 SMTP,特别是涉及认证和 SSL/TLS 时,强烈推荐使用更现代的模块,例如 Email::Sender::Transport::SMTP::TLS(Email::Sender 生态系统的一部分),因为它们更健壮地处理这些复杂性。MIME::Lite 的直接 SMTP 支持在满足现代安全要求时可能很棘手。

现代替代方案:Email::Stuffer 或 Email::Sender

Section titled “现代替代方案:Email::Stuffer 或 Email::Sender”

对于新的 Perl 项目,可以考虑以下更现代的模块:

  • Email::Stuffer:一个流行的选择,因其简单流畅的接口用于创建和发送电子邮件,包括 HTML、文本部分和附件。它底层通常使用 Email::Sender。
  • Email::Sender:一个灵活的电子邮件发送系统,支持各种传输方式(SMTP, sendmail 等),并良好支持现代 SMTP 功能,如 SSL/TLS 和认证。

使用 Email::Stuffer 的示例(概念性):

#!/usr/bin/perl
use strict;
use warnings;
use Email::Stuffer;
# Conceptual example - details depend on your SMTP setup
# 概念性示例 - 具体细节取决于你的 SMTP 设置
my $email = Email::Stuffer->from('sender@example.com')
->to('recipient@example.com')
->subject('Modern Perl Email Test')
# 现代 Perl 电子邮件测试
->text_body('Hello from Email::Stuffer!')
# 来自 Email::Stuffer 的问候!
->html_body('<h1>Hello from Email::Stuffer!</h1>')
# <h1>来自 Email::Stuffer 的问候!</h1>
->attach_file('./report.pdf');
# To send via SMTP, you might need to configure transport or use Email::Sender directly
# 要通过 SMTP 发送,你可能需要配置传输方式或直接使用 Email::Sender
# $email->send; # Default send might use sendmail
# 默认发送可能使用 sendmail
try {
# Example of sending via Email::Sender with specific transport:
# 使用 Email::Sender 通过特定传输方式发送的示例:
use Email::Sender::Simple qw(sendmail);
use Email::Sender::Transport::SMTP;
my $transport = Email::Sender::Transport::SMTP->new({
host => 'smtp.example.com',
port => 587,
# ssl => 'starttls', # or true for SMTPS on port 465
# 或 true 表示端口 465 上的 SMTPS
# sasl_username => 'user',
# sasl_password => 'pass',
});
sendmail($email->as_email_mime, { transport => $transport });
print "Email sent with Email::Stuffer via SMTP!\n";
# 使用 Email::Stuffer 通过 SMTP 发送电子邮件!
}
catch {
warn "Failed to send email with Email::Stuffer: $_\n";
# 使用 Email::Stuffer 发送电子邮件失败:$_\n
};

请务必查阅你选择的特定电子邮件模块的文档,因为 SMTP 服务器、认证和加密的配置可能有所不同。