Sunday, March 24, 2013

Nullmailer on Raspberry Pi

Edit: 2013-03-28 - Nullmailer Problems

  • There are some problems with nullmailer that caused me to change to Postfix. I've written about setting up PostFix here.

    Nullmailer continues to attempt to send even permanently rejected mails every time the queue handler runs. I suppose it would be possible to write a script to delete queued items over a certain age and synchronise this with Nullmailer. But given the limitations that Nullmailer's minimalist implementation imposes, I switched to using Postfix with a null (send only) setup.


At some point you are probably going to want to send email from your Raspberry Pi. If for nothing else, it would be nice to receive the system notifications that processes often mail to 'root' or the login user.

My own need to setup a mail system has arisen because I want to schedule jobs using cron as part of a project.

By default, if a job scheduled using cron fails, its output is mailed to the running user (normally root).  I want this email to be delivered to an external user, rather than sitting in the root mailbox on my Pi.

I find my favourite tool for this is a simple mail transport agent called nullmailer. I've used the tool in the past on other systems but thought I'd check Google for any Raspberry Pi specific advice. I was surprised to find setup and configuration descriptions were sparse so I put the following together using a smattering of experience and the application help produced by the following:

man nullmailer-queue
man nullmailer-inject
man nullmailer-send
/usr/lib/nullmailer/smtp --help
/usr/lib/nullmailer/qmqp --help

Installation

You can install nullmailer on Raspbian Wheezy with the usual:

sudo apt-get update
sudo apt-get install nullmailer

During installation you will be asked for your required hostname and a remote mailer. You can just accept the (probably non-working) defaults for now.

Once nullmailer is installed, we can configure it. Configuration is achieved by amending or creating several configuration files. All but one of the nullmailer configuration files (/etc/nullmailer/remotes) contains a single line with one entry.

Quick Setup Using a Google Mail Account

Edit the file /etc/nullmailer/remotes using nano

sudo nano /etc/nullmailer/remotes

It should contain a single line containing the following parameters (replaced with your Google account and password, of course). The examples cover two or more lines due to restrictions of the web page format. You must put all the arguments on a single line in your configuration file. 

smtp.gmail.com smtp --port=465 --auth-login --user=you@gmail.com 
                    --pass=password --ssl

Optionally, if you want mail for local users ('root', 'pi' etc) to be forwarded to an external address, edit /etc/nullmailer/adminaddr so that it contains a single line with your forwarding email address in it.

Finally, by default nullmailer will retry any failed messages once every minute. This is undesirable. We only want to try and send a message once.

sudo nano /etc/nullmailer/pausetime

Enter the number 0 in this file to put nullmailer in one shot mode and save the file. It will still try to send all outstanding messages every time the system adds a new one to the queue, but this is OK.

Restart nullmailer

sudo /etc/init.d/nullmailer restart

You are ready to go. Test that  you can send email with:

echo "My Test Message" | sendmail youremail@yourdomain.com

Detailed Configuration

After a default installation on Raspbian Wheezy, the following configuration files will have been created:
  • /etc/mailname
  • /etc/nullmailer/adminaddr
  • /etc/nullmailer/defaultdomain
  • /etc/nullmailer/remotes
Nullmailer also uses the following optional configuration files that you may create and edit:
  • /etc/nullmailer/me
  • /etc/nullmailer/defaulthost
  • /etc/nullmailer/helohost
  • /etc/nullmailer/idhost
  • /etc/nullmailer/pausetime
  • /etc/nullmailer/sendtimeout
After you have edited any configuration files, always restart nullmailer with

sudo /etc/init.d/nullmailer restart

/etc/nullmailer/me

This file is used on systems that don't have /etc/mailname present. Your Rasbian Wheezy has /etc/mailname present so you can ignore this config file. Delete /etc/nullmailer/me if you have created one during a previous configuration of nullmailer.

/etc/mailname

This is normally the same as the output from /bin/hostname. Some programs may use this file to create the domain part of an email address. You can leave this at the system default if you are sending out mail from an email account such as your Google mail account.

If you are using a remote smtp smarthost and you have an entry in /etc/nullmailer/adminaddr you may have to reconfigure the hostname in this file. Programmes such as the 'cron' scheduler will use the value in /etc/mailname to form their 'from' address. Nullmailer does not rewrite full domain addresses where they exist. If your /etc/mailname contains a host name that does not really exist, such as 'raspberrypi.somedomain', then this is used as the from address (and therefore the default reply-to address). The smtp server you are connecting to may reject your mail if it cannot establish a viable return address.

If you are using an external smart smtp relay then your only option is probably to put your real domain name that accepts your email here. For example, for me that would be 'znix.com'.  When you read through the descriptions of the other configuration files below remember that for my case because I have 'znix.com' in /etc/mailname, programs such as 'cron' will send mail To root@znix.com, From root@znix.com. Nullmailer will regard the To address as being for a local user ( the domain is in /etc/mailname ) and so will send it to the email address in /etc/adminaddr. The smtp relayer will see 'znix.com' as a valid return mail host so will accept the mail.

With an internal smart smtp host you can set up that host to rewrite the from and reply-to addresses for mail coming from your internal network.

/etc/remotes

This file contains a list of remote email servers that you wish to send your outgoing mail to. When mail is ready to be sent, nullmailer will try each of the configured servers in turn until it succeeds in sending the mail. If all servers fail, nullmailer will leave the messages in a queue and attempt the process again after the period specified in /etc/nullmailer/pausetime.

Note: Any of the configuration entries below must appear in /etc/nullmailer/remotes as a single line for each server entry.

The basic format for a server entry in /etc/nullmailer/remotes is:
mail.domain.com smtp

however, you are unlikely to have a mail server that accepts direct unauthenticated connections on port 25 so nullmailer allows you to pass several parameters to control how you connect to the server.

server requires plain authentication (unusual)
mail.domain.com smtp --port=25 --user=you --pass=passwd

server requires login authentication
mail.domain.com smtp --port=587 --auth-login --user=you@isp.com 
                     --pass=passwd

server supports TLS login authentication
mail.domain.com smtp --port=587 --auth-login --user=you@isp.com 
                     --pass=passwd --starttls

server listens on SSL port
mail.domain.com smtp --port=465 --auth-login --user=you@isp.com
                     --pass=passwd --ssl

Some ISP's set up their mail servers using SSL certificates with common names like *.domain.com. If nullmailer is connecting to the server mail.domain.com then it will regard any certificate with a common name other than mail.domain.com as insecure (correctly) and will not send your login details. You can pass an option so that nullmailer accepts any SSL certificate. In this case you are only using the certificate to encrypt your login details and not relying on it to identify the remote server.

accept unverified ssl certificate
mail.domain.com smtp --port=465 --auth-login --user=you@isp.com 
                     --pass=passwd --ssl --insecure

The nullmailer version in Raspbian Wheezy can also handle authentication using client SSL certificates over SSL / TLS.  The following options can be added to your server line in /etc/nullmailer/remotes


--x509certfile=<client certificate file>
--x509cafile=<path to certificate authority ca file>
               (default /etc/ssl/certs/ca-certificates.crt)
--x509crlfile=<certificate revocation list (crl)>
--x509fmtder   nullmailer expects files in PEM format. use 
               this flag if x509 files are in DER format.        

Nullmailer also supports the QMQP protocol. Just replace 'smtp' with 'qmqp' in your /etc/nullmailer/remotes configuration line(s).


Google Mail Remotes Recipe

either of the following will work in the remotes file to use a Google mail account to send email.
smtp.gmail.com smtp --port=587 --auth-login --user=you@gmail.com 
                    --pass=password --starttls

smtp.gmail.com smtp --port=465 --auth-login --user=you@gmail.com 
                    --pass=password --ssl

/etc/nullmailer/adminaddr

Processes on your Raspberry Pi that create emails will send them to the local user running the process. The email address will normally be created by prepending the login name to either 'localhost', the output of /bin/hostname or the content of /etc/mailname.

For example;
    root@localhost
    pi@raspberrypi.local

If you put an email address in /etc/nullmailer/adminaddr, then all email addressed to any user at the domains 'localhost' or the domain contained in /etc/mailname will be sent to the email address you enter. For example, if /etc/nullmailer/adminaddr contains

myname@gmail.com

Then mail for root@localhost will be sent to myname@gmail.com. If the content of /etc/mailname is raspberrypi then any mail address to, for example, pi@raspberrypi will be sent to the address in /etc/nullmailer/adminaddr.

/etc/nullmailer/defaulthost

If you are using an email account such as your Google mail account to send mail, then this file is not essential. It may be useful if you use your ISP's smtp server or if you are using a local smtp server.

If this file contains a hostname, then any email address that does not contain any hostname will have this host appended. This applies to all addresses ( From, To, Cc, etc). If nullmailer receives an email addressed to 'root' from 'pi' and /etc/nullmailer/defaulthost contains 'myraspberry.mydomain.net' then the addresses will be changed to 'root@myraspberry.mydomain.net' and 'pi@myraspberry.domain.net'.

If the file /etc/nullmailer/defaulthost is empty, then the domain in /etc/mailname is used.

On my own system I have a local smtp host that then relays mail to my ISP's smtp relay. The ISP smtp relay is fussy about the reply-address in the mail being a resolvable host. I set my /etc/nullmailer/defaulthost file to contain znix.com so the mail from my raspberries appears to come from root@znix.com or pi@znix.com. On the receiving end I have filters set up to reject mail addressed to 'root' unless it originates from one of the raspberries.

/etc/nullmailer/defaultdomain

If you are using an email account such as your Google mail account to send mail, then this file is not essential. It may be useful if you use your ISP's smtp server or if you are using a local smtp server.

If this file contains a domain name, then any email address that does not contain a hostname that includes a full stop ( period ) other than 'localhost' will have this domain appended.  This includes any hostname taken from /etc/nullmailer/defaulthost or /etc/nullmailer/idhost.

This applies to all addresses ( From, To, Cc, etc). If nullmailer receives an email addressed to 'root@raspberry' from 'pi@localhost' and /etc/nullmailer/defaultdomain contains 'mydomain.net' then the addresses will be mapped to 'root@raspberry.mydomain.net' and 'pi@localhost'.

If the file /etc/nullmailer/defaultdomain is empty, then the domain in /etc/mailname is used.

As an example of how the defaultdomain and defaulthost files work together:

defaulthost         myrasberry
defaultdomain       mydomain.com
mapping: from to
root                root@myraspberry.mydomain.com
root@other          root@other.mydomain.com
root@other.place    root@other.place


defaulthost         myrasberry.com
defaultdomain       mydomain.com
mapping: from to
root                root@myraspberry.com
root@other          root@other.mydomain.com
root@other.place    root@other.place

/etc/nullmailer/idhost

If you are using an email account such as your Google mail account to send mail, then this file is not essential.

The file allows you to set the content of the suffix that nullmailer uses when creating message id's for each mail sent. By default, the content of /etc/nullmailer/defaultdomain is used. If required you would normally put a fully qualified domain name (not necessarily real) in here. The message id does not matter outside your system but it is visible in the headers of the mail when sent.

/etc/nullmailer/helohost

You only need this file if you are relaying through an smtp smarthost that won't accept your default domain as a valid mail server. By default, nullmailer uses the value from /etc/mailname for the HELO message in the smtp protocol. Any domain set in this file will be used in the HELO message instead.

/etc/nullmailer/pausetime

This config file may prove particularly useful for your setup on the Raspberry Pi. It contains the  number  of  seconds to pause between successive queue runs when there are messages in the queue (defaults to 60 if this file not present). You should always create this file and enter some value. If you want to retry failed email I would recommend waiting an hour between retry attempts ( enter 3600 in this file ).

However, if  this is set to 0, nullmailer will exit immediately after attempting to send mail once (one-shot mode). This may be desirable if your Pi is only intermittently connected to the network. Without a network connection nullmailer will by default keep attempting to send your mail once every 60 seconds and will write entries for every attempt in your system logs.

By putting the value 0 in /etc/nullmailer/pausetime, nullmailer will attempt to send each mail added to the queue just once. You must attempt to resend queued mail manually.

Any user can trigger an attempt to send all mail waiting in the queue manually at any time by writing a single byte to the /var/spool/nullmailer/trigger pipe. For example:

echo 1 > /var/spool/nullmailer/trigger

will cause nullmailer to attempt to send all messages in the queue.

/etc/nullmailer/sendtimeout

You don't need to set this file unless you have a very specific requirement. The file contains the  number of seconds to wait to complete sending a message before killing the attempt and trying  again (defaults to 3600 if this file not present).  If this is set to 0, nullmailer will wait forever for messages to complete sending (probably a very bad thing).

Summary

If you are using an email account such as your Google mail account to send email, then much of the configuration concerned with address munging does not really matter to you. You may only need to configure /etc/nullmailer/remotes to set your ISP server and /etc/nullmailer/adminaddr if you want local mail forwarding somewhere. Conversely, if you are communicating with a smart smtp relay then applying address mapping and identification settings that result in routable email addresses is probably essential. Hopefully nullmailer can be configured to suit your needs.

In either case, the capability to switch on manual queue delivery using /etc/nullmailer/pausetime should prove useful for many projects where the Pi has an intermittent network connection.