How To Send Email through an External SMTP Service with Sendmail on FreeBSD 10.1
One of the most common needs when setting up a new web server is sending email. The safest and easiest way to do this is to connect your server to a mailing service such as SendGrid or Amazon SES. Using an external service will help you avoid pitfalls like your server IP getting blacklisted by anti-spam services.
In this tutorial we'll go over how to connect FreeBSD's built-in Sendmail service to SendGrid to send emails from your server. You can also adapt the settings for a different external mail service without much trouble.
If you're new to FreeBSD, some of what we do may look a little scary, but you'll soon be comfortable rolling up your sleeves to do a little recompiling of system tools like the FreeBSD pros.
In this tutorial, we will:
- Recompile Sendmail with SASL support so the server can authenticate with an external service
- Configure the Sendmail mail server with the appropriate settings
- Test outbound email to make sure mail is going out from your server
Before you begin this guide you'll need the following:
- A FreeBSD 10.1 Droplet
- Access to your root account or an account with sudo privileges following this tutorial
- Working knowledge of how to edit text files from the command line
- You should install your favorite text editor, such as
- A free SendGrid account for testing purposes, or another mail provider that gives you SMTP details for the service. You will need these details for your external mail provider:
- SMTP hostname
- Your server's hostname, which you can find by running
This tutorial is most easily followed as root:
Step 1 — Set Up Package Management
First, we need to recompile Sendmail so it can authenticate with an external mail service - in this case, SendGrid.
All of the steps are included here, but if you like, you can follow along with the official FreeBSD handbook.
Some software will be compiled from FreeBSD's Ports Collection, so we need to make sure that is up to date first.
portsnap fetch && portsnap update
The Portmaster utility will let us easily compile software from the Ports tree, so let's get that installed.
pkg install portmaster
Run the following command to make sure the system knows to install newly compiled packages in the latest package format for FreeBSD.
echo 'WITH_PKGNG=yes' >> /etc/make.conf
Step 2 — Install and Configure the SASL Package
Using our newly installed Portmaster utility, compile and install the
cyrus-sasl2 package with the following command. This is used for authentication with the external mail service.
When prompted, ensure LOGIN is checked, which should be by default. Choose OK and press
ENTER twice to choose all the defaults. When prompted, answer
y to upgrade and install your packages. You should expect a large amount of output, ending with:
Output===>>> Done displaying pkg-message files ===>>> The following actions were performed: Upgrade of pkg-1.4.12 to pkg-1.5.0 Upgrade of perl5-5.18.4_11 to perl5-5.18.4_13 Installation of security/cyrus-sasl2 (cyrus-sasl-2.1.26_9)
Edit the file (creating it if it does not already exist)
/usr/local/lib/sasl2/Sendmail.conf and add the following to it:
Next, install the
saslauthd service for SASL authentication. When prompted, accept the defaults and choose OK.
Edit the system configuration file
/etc/rc.conf and add the following configuration parameters at the end of the file. Replace
your_hostname with your server's hostname.
hostname = "your_hostname" sendmail_enable="YES" saslauthd_enable="YES"
Now start the
service saslauthd start
You should see this output:
Outputusage: hostname [-fs] [name-of-host] usage: hostname [-fs] [name-of-host] Starting saslauthd.
/etc/make.conf file, adding the following parameters so the system knows which SASL Sendmail options to use.
SENDMAIL_CFLAGS=-I/usr/local/include/sasl -DSASL SENDMAIL_LDFLAGS=-L/usr/local/lib SENDMAIL_LDADD=-lsasl2
Step 3 — Recompile Sendmail with SASL Support
In this section we'll recompile Sendmail to use SASL authentication.
Now we need to sync the latest source code for FreeBSD 10.1.
First, we'll install Subversion so we can easily get the source code we need.
pkg install subversion
Now we can check out the latest code for recompiling, directly from the FreeBSD project website, to update our sources in
svn co http://svn.freebsd.org/base/releng/10.1/ /usr/src
The next commands you need to run in succession, one group at a time. What we are doing here is telling the system to recompile (or rebuild) the built-in Sendmail packages with our new security and login requirements, and then reinstall Sendmail.
cd /usr/src/lib/libsmutil make cleandir && make obj && make
cd /usr/src/lib/libsm make cleandir && make obj && make
cd /usr/src/usr.sbin/sendmail/ make cleandir && make obj && make && make install
Step 4 — Configure Sendmail
You've made it this far, and we're done recompiling things. Let's keep going!
For this next step we'll walk through a basic Sendmail configuration that will tell Sendmail to route all outbound mail through our selected external smart hosting service.
First we're going to be safe and create a backup of the
cp -a /etc/mail /etc/mail.bak
Enter the mail configuration directory.
Run the following command to generate a basic mail configuration.
Create and edit the
relay-domains file, adding the following parameters. Replace
your_server.example.com with your FQDN, and
example.com with your domain name.
Create and edit the
local-host-names file, adding the following parameters. Replace the variables with your local hostnames.
Create and edit the
access file, adding the following parameters. (Note you'll need to change the
smtp.sendgrid.net address if you're using a provider other than SendGrid.)
smtp.sendgrid.net OK GreetPause:localhost 0
Create and edit the
authinfo file, adding the following parameters. Replace
smtp_password with your SendGrid account name and password. If you elected to use a different external mail provider, you'll also need to change the
smtp.sendgrid.net value on both lines to the server address for your provider.
AuthInfo:smtp.sendgrid.net "U:root" "I:smtp_username" "P:smtp_password" "M:LOGIN" AuthInfo:smtp.sendgrid.net:587 "U:root" "I:smtp_username" "P:smtp_password" "M:LOGIN"
authinfo files are really going to be simple databases from which Sendmail reads configuration parameters. This may sound confusing, especially if you're new to FreeBSD and Sendmail, but you just need to run these two painless commands from the
/etc/mail/ to generate the databases.
makemap hash access < access makemap hash authinfo < authinfo
Now we'll edit the base configuration we generated a few commands aback. Edit the
your_server.mc file. (You can
/etc/mail/ directory if you're not sure of the file name.)
Insert the following configuration lines between the
your.isp.mail.server') block and the
dnl Uncomment the first line to change the location of the default block as shown below.
You'll need to change the
smtp.sendgrid.net address to your provider's server address if you're not using a SendGrid account like in the example. You'll also need to update the two instances of
example.com to the domain you'd like the mail to be from. (Note that you may need to set appropriate TXT, DKIM, PTR etc. records to avoid reports of spoofing.)
dnl define(`SMART_HOST', `your.isp.mail.server') dnl SET OUTBOUND DOMAIN MASQUERADE_AS(`example.com') MASQUERADE_DOMAIN(example.com) FEATURE(masquerade_envelope) FEATURE(masquerade_entire_domain) dnl SMART HOST CONFIG define(`SMART_HOST', `smtp.sendgrid.net')dnl define(`RELAY_MAILER_ARGS', `TCP $h 587')dnl define(`confAUTH_MECHANISMS', `GSSAPI DIGEST-MD5 CRAM-MD5 LOGIN PLAIN')dnl FEATURE(`authinfo',`hash /etc/mail/authinfo.db')dnl TRUST_AUTH_MECH(`GSSAPI DIGEST-MD5 CRAM-MD5 LOGIN PLAIN')dnl dnl Uncomment the first line to change the location of the default
Before we apply the changes, let's walk through a bit of the above configuration. The first block is telling Sendmail that we'd like to make sure it appears that our outbound mail is coming from our domain
The second block is defining where we want to smart host our mail to, including the port, authentication methods, and our authentication info that we set up in a previous step. Notice that we're referencing the
Now let's apply the changes we've made. Make sure you're still in the
/etc/mail/ directory. Make sure Sendmail is started:
service sendmail start
Updating our configuration:
make make install restart
service sendmail restart
Our Sendmail configuration is done. The next step is to send a test email.
Step 5 — Send a Test Email
Now that we have gone through all the steps for a proper setup, let's make sure that everything is working.
mailx command to send a test message to a real email account you use every day.
When prompted, enter
test or whatever you want for a subject, and then press
You'll then be presented with just a cursor and the ability to write the body of your test email. Just write the single word
test again and press
You need to tell
mailx that you're done writing your message; to do that we have to end the message with a single
. and press
ENTER one final time. You'll immediately see
EOT as confirmation of that.
Next, run the the following command to check that the mail queue is empty and that our message has been sent.
The output should look like this if our test message has been successfully sent, and you should see it in your inbox shortly.
/var/spool/mqueue is empty Total requests: 0
Go check your email now to make sure the message arrived. It should be from firstname.lastname@example.org.
Blindly trusting the fact that the mail queue is empty is not a valid test of success. Even if you've already received the message, you're going to want to know the basics in viewing your mail logs. Run the following command.
tail -f /var/log/maillog
The two keys you're looking for in the log output are
Sent (<message id> Message accepted for delivery)
relay=smtp.sendgrid.net. [18.104.22.168], dsn=2.0.0, stat=Sent (Delivery in progress)
Make sure you can spot these messages in the log output below.
Mail LogFeb 11 04:09:13 your_server sm-mta: t1B49CW0049080: from=<freebsd@your_server>, size=331, class=0, nrcpts=1, msgid=<201502110409.t1B49CZ4049079@your_server>, proto=ESMTP, daemon=Daemon0, relay=localhost [127.0.0.1] Feb 11 04:09:13 your_server sendmail: t1B49CZ4049079: email@example.com, ctladdr=freebsd (1001/1001), delay=00:00:01, xdelay=00:00:01, mailer=relay, pri=30040, relay=[127.0.0.1] [127.0.0.1], dsn=2.0.0, stat=Sent (t1B49CW0049080 Message accepted for delivery) Feb 11 04:09:13 your_server sm-mta: STARTTLS=client, relay=smtp.sendgrid.net., version=TLSv1/SSLv3, verify=FAIL, cipher=AES128-GCM-SHA256, bits=128/128 Feb 11 04:09:13 your_server sm-mta: t1B49CW0049080: to=<firstname.lastname@example.org>, ctladdr=<freebsd@your_server> (1001/1001), delay=00:00:00, xdelay=00:00:00, mailer=relay, pri=30331, relay=smtp.sendgrid.net. [22.214.171.124], dsn=2.0.0, stat=Sent (Delivery in progress)
This shows that your message has been accepted and is on its way to your inbox, which may be a bit anticlimactic if you've already received it.
To do live testing and troubleshooting, you can have two terminal sessions open and leave the
tail -f /var/log/maillog command running in one, while you send test messages in the other.
You're now ready to start sending outbound email from your FreeBSD Droplet via SendGrid or any other mail service you like. Any web sites or web applications you deploy will now be able to take advantage of this with minimal to no configuration.
If you have any questions or comments, please leave them below.