Getting email off my web server with msmtp (and PHP)

Sometimes I want to get a message from my server, e.g. diagnostic stuff from services (SMART daemon, fail2ban), or if someone tries to contact me on my website, and I want it sent to one of my email addresses which is not maintained on that server.

I used to use sSMTP for this, but it seems to stop working about once a year, is mostly unmaintained and said to be insecure.

So now I switched to msmtp. Here's how to set it up as a drop-in replacement for sendmail (just like sSMTP was), so system utilities and PHP can use it.

msmtp

Be aware that some settings depend on the email provider that provides the email address used to send these mails.

apt install msmtp msmtp-mta # the latter provides the sendmail binary

Do not create a config file in ~/.msmtprc but instead edit /etc/msmtprc only.

#> cp /usr/share/doc/msmtp/examples/msmtprc-system.example /etc/msmtprc

Example (you can get port, host and TLS settings from your provider's email client configuration):

grep -vE '^#|^$' /etc/msmtprc
account default
host domain.com
port 465
tls on
tls_starttls off
syslog LOG_MAIL
from user@domain.com
auth on
user user@domain.com
password xxxxxxxxxxxxxxxxxxxxxx

Test:

echo asdasdasdasd | sudo -u www-data msmtp recipient@domain.tld

Since PHP is using /usr/sbin/sendmail -t -i by default, let's try that:

echo asdasdasdasd | sudo -u www-data /usr/sbin/sendmail -t -i recipient@domain.tld

Did it work? Then let's switch to secure password storage at this point. Most msmtp tutorials use GPG for that. We probably need to initialise GPG first for the www-data user:

sudo -u www-data gpg --full-gen-key

Don't use any passphrases; but keep in mind not to ever use this key for anything else.

If you get this error:

gpg: agent_genkey failed: Permission denied

- try this solution:

ls -l $(sudo -u www-data tty)
sudo chown www-data $(sudo -u www-data tty)

After you're done with the GPG stuff, change ownership back to the original user (if applicable - for me, it reverted after I closed/re-opened the ssh session).

Generate the GPG password file (do this in a tmpfs to avoid leaving traces on your hard drive):

cd /dev/shm
printf '%s' emailaccountpassword > some_file
sudo -u www-data gpg --default-recipient-self -e some_file
mv some_file.gpg /etc/msmtp.pw
rm some_file
chmod 400 /etc/msmtp.pw

Now let's replace the password ... line in /etc/msmtprc with this:

passwordeval gpg --quiet --for-your-eyes-only --no-tty --decrypt /etc/msmtp.pw

Obviously there's still a security issue here, but ultimately there will always remain one if we want to fully automate this and never enter a password manually.

If you intend to use the key pair generated for www-data for anything else, this might not be the best solution. Otherwise, I think it's sufficiently secure. Please contact me if you think otherwise.

Lastly:

chmod 400 /etc/msmtp*
chown www-data:www-data /etc/msmtp*

Now try again to send an email, as above.

If that worked, try again from your website's contact form. If that doesn't work, you need to go searching for helpful log entries. There's /var/log/mail.* which might provide the answers you need. After that it's server logs.

PHP Configuration

PHP by default relies on sendmail to send out e-mail (you can check with grep sendmail_path -r /etc/php*), and most contact form plugins or code snippets rely on that. If you find this configuration option to be commented out (or not present at all) you can check with phpinfo(); most likely you will see sendmail_path /usr/sbin/sendmail -t -i.

This should be enough to make it work. A quick test:

php
<?PHP $sender = 'you@mail.tld'; $recipient = 'you@mail.tld'; $subject = "php mail test"; $message = "php test message"; $headers = 'From:' . $sender; if (mail($recipient, $subject, $message, $headers)) { echo "Message accepted"; } else { echo "Error: Message not accepted"; } ?>

Further reading

https://wiki.debian.org/msmtp
https://wiki.archlinux.org/title/Msmtp

Possible alternative to GPG: openssl

To test, let's disable msmtp's apparmor profile (which disallows executing openssl):

#> apparmor_parser -R /etc/apparmor.d/usr.bin.msmtp
#> # check if it worked:
#> aa-status

Analogous to the process outlined above, create an encrypted password in a file with this command:

openssl enc -aes-256-cbc -iter 99999 -a -pass env:USER -out some_file

Type your password, and finish with Enter, then Ctrl-D.

Change the passwordeval line in /etc/msmtprc:

passwordeval openssl enc -aes-256-cbc -iter 99999 -a -pass env:USER -d -in some_file

Does it work? I'm not sure how to best edit the apparmor profile without completely disabling it. For now, re-enable it thusly:

#> apparmor_parser /etc/apparmor.d/usr.bin.msmtp
#> # check if it worked:
#> aa-status