Problems with and solutions to sending e-mail with Perl.
Repeated far too often in code, despite flaws and limitations. Do not use!
open SENDMAIL, "|/usr/sbin/sendmail -t"
or die "$0: fatal: could not open sendmail: $!\n";
print SENDMAIL "To: user\@example.org\n";
print SENDMAIL "Subject: message\n\n";
print SENDMAIL "Message body\n";
close SENDMAIL;
Problems include:
Net::SMTP is another module I dislike: it does not support Mail Exchange (MX) records, and thus to avoid a single point of failure—the single host the module connects to—requires wrapping with additional code that looks up MX records, handles various temporary or permanent send failures, queues temporarily failed messages, and otherwise begins to poorly implement a proper Mail Transport Agent (MTA). The portable, scalable method, below, passes e-mail off to a local MTA, which handles the (many!) delivery complications of the Simple Mail Transport Protocol (SMTP). If the code cannot be fixed to not rely on a single host, then time must be wasted setting up a highly available address, usually via some expensive network device or complicated software load balancer, and a likely higher risk of e-mail delivery failure accepted.
Among the many Perl modules available on Comprehensive Perl Archive Network (CPAN) for sending e-mail, I favor MIME::Lite. Easy to use, easy to attach new content, and easy to send the message elsewhere for debugging:
use MIME::Lite;
my $message = MIME::Lite->new(
To => 'user@example.org',
Subject => 'message',
Data => 'Message body'
);
$message->send();
$message->attach(
Type => 'image/gif',
Path => $filename,
Disposition => 'attachment'
);
$message->send();
if ($use_stdout) {
$message->print( \*STDOUT );
} else {
$message->send();
}
Consider also the Email::Stuff module, which provides great ease of use for common tasks.
Never build up a message into a scalar, then print the scalar. HTML errors become difficult and time consuming to debug in longer messages, and extending or reformatting the look of the message is nearly impossible.
my $message_body = '<html></body>';
$message_body .= '<B>This is as ugly as it looks</B';
if ($printer_on_fire) {
$message_body .= "<p>More <a href=\"ugh\">horrors</a>";
}
Instead, template the message with HTML::Template or similar module. This abstracts the data properly away from the content. At the very least, stop backslashing doublequotes in doublequoted strings:
my $ugly = "<a href=\"$url\">$link_text</a>";
my $link = qq{<a href="$url">$link_text</a>};