How to correctly set the From address on email that is sent from your website

A lot of our customers run into trouble with email sent from their websites -- FormMail, or custom code. The problem is that the envelope-from address is often not set. If our customers or the recipients of these incorrectly formatted emails hit reply, sometimes the replies disappear into the ether (well actually they come to us but we can't possibly deal with them all so it's the same thing). More importantly though, if the emails bounce - ie the address it was sent to isn't working - the bounce will go to the web hosting provider - yes we get a lot of these, which leads us to the original internal title of this article "How to Send Email from Websites Without Pissing Off Anchor"

Firstly, a bit of theory.

Messages contain two sections: the headers and the body. The headers most people are familiar with, and contains a To: address, and a From: address, in addition to many other headers. This is analogous to a formal letter in which the sender and recipient are printed on the same page as the message.

In addition to this, the MTA also keeps envelope information, analogous to the envelope that the letter is posted in. This is what the MTA uses when conducting an SMTP transaction, i.e. the MAIL FROM command, and RCPT TO commands use data from the envelope to instruct the destination MTA who the message is from and where to send it.

The envelope from address can be different to the message from.

Here's a typical message header:

Return-Path: anchor@starboard.anchor.net.au
Received: from mail.anchor.net.au [202.4.236.106]
        by localhost with IMAP (fetchmail-6.2.5)
        for jaq@localhost (single-drop); Wed, 08 Mar 2006 07:01:35 +1100 (EST)
Received: (from anchor@localhost)
        by starboard.anchor.net.au (8.11.6/8.11.6) id k27K0iK27993
        for tech-staff; Wed, 8 Mar 2006 07:00:44 +1100
Received: from av1.puremail.com.au (av1.puremail.com.au [202.4.234.193])
        by starboard.anchor.net.au (8.11.6/8.11.6) with ESMTP id k27K0g427949
        for <root@anchor.net.au>; Wed, 8 Mar 2006 07:00:42 +1100
Received: from bosun.anchor.net.au (unknown [202.4.234.196])
        by av1.puremail.com.au (Spam Firewall) with ESMTP id C625320002D3
        for <root@anchor.net.au>; Wed,  8 Mar 2006 07:00:41 +1100 (EST)
Received: by bosun.anchor.net.au (Postfix, from userid 0)
        id 5E37060D82; Wed,  8 Mar 2006 07:00:41 +1100 (EST)
To: root@anchor.net.au
Subject: Anchor Update Check bosun.anchor.net.au
From: root <root@bosun.anchor.net.au>

The envelope sender is marked at the destination by the Return-Path field, and is also the address that will receive bounces to messages from the MTA, if the To: address doesn't exist.

How to do it right

The main problem customers have is that they are not setting the envelope-from address, thinking that merely setting From: will suffice. As noted above, this is not sufficient and bounces will return to the web server, not the place they are expecting.

Directly with Sendmail

You specify the envelope from address with the -f flag to sendmail, e.g.:

/usr/bin/sendmail -t -i -f "sender@example.org" <<EOF
From: Someone <sender@example.org>
To: recipient@example.org
Subject: Some subject here

Some body text here
EOF

Via Perl

use MIME::Lite;

$msg = MIME::Lite->new(
                From     =>'me@myhost.com',
                To       =>'you@yourhost.com',
                Cc       =>'some@other.com, some@more.com',
                Subject  =>'Some subject here!',
                Data     =>"Some body text here"
                );


$msg->send;

In the rare case that the send method doesn't set the envelope sender to the value in the From: of the message, then you can instead call:

$msg->send_by_sendmail(FromSender => 'me@myhost.com');

Via PHP

For PHP, you need to explicitly set the envelope sender when sending, at least according to the documentation.

<?php
mail('nobody@example.com', 'the subject', 'the message', null, '-f webmaster@example.com');
?> 

Via Python

   1 import smtplib
   2 
   3 from_address = "sender@example.org"
   4 to_addresses = [ "recipient@example.org", "other@example.org" ]
   5 
   6 message = """From: Sender <sender@example.org>
   7 To: recipient@example.org, other@example.org
   8 Subject: Some subject
   9 
  10 Some body
  11 """
  12 
  13 s = smtplib.SMTP()
  14 s.connect()
  15 s.sendmail(from_address, to_addresses, message)
  16 s.close()