We hope you find this tutorial helpful. In addition to guides like this one, we provide simple cloud infrastructure for developers. Learn more →

How To Send Email through an External SMTP Service with Sendmail on FreeBSD 10.1

PostedApril 22, 2015 92.4k views Email FreeBSD

Introduction

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.

Goals

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

Prerequisites

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 nano or vim
  • 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
    • username
    • password
  • Your server's hostname, which you can find by running hostname

This tutorial is most easily followed as root:

sudo su

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.

portmaster security/cyrus-sasl2

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:

vim /usr/local/lib/sasl2/Sendmail.conf
/usr/local/lib/sasl2/Sendmail.conf
pwcheck_method: saslauthd

Next, install the saslauthd service for SASL authentication. When prompted, accept the defaults and choose OK.

portmaster security/cyrus-sasl2-saslauthd

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.

vim /etc/rc.conf
/etc/rc.conf
hostname = "your_hostname"
sendmail_enable="YES"
saslauthd_enable="YES"

Now start the saslauthd service.

service saslauthd start

You should see this output:

Output
usage: hostname [-fs] [name-of-host] usage: hostname [-fs] [name-of-host] Starting saslauthd.

Edit the /etc/make.conf file, adding the following parameters so the system knows which SASL Sendmail options to use.

vim /etc/make.conf
/etc/make.conf
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 /usr/src.

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 /etc/mail directory.

cp -a /etc/mail /etc/mail.bak

Enter the mail configuration directory.

cd /etc/mail

Run the following command to generate a basic mail configuration.

make

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.

vim /etc/mail/relay-domains
/etc/mail/relay-domains
your_server.example.com
example.com

Create and edit the local-host-names file, adding the following parameters. Replace the variables with your local hostnames.

vim /etc/mail/local-host-names
/etc/mail/local-host-names
your_server
your_server.example.com

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.)

vim /etc/mail/access
/etc/mail/access
smtp.sendgrid.net      OK
GreetPause:localhost    0

Create and edit the authinfo file, adding the following parameters. Replace smtp_username and 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.

vim /etc/mail/authinfo
/etc/mail/authinfo
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"

The access and 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 ls the /etc/mail/ directory if you're not sure of the file name.)

vim /etc/mail/your_server.example.com.mc

Insert the following configuration lines between the dnl define(SMART_HOST', 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.)

your_server.example.com.mc'>/etc/mail/your_server.example.com.mc
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 example.com.

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 /etc/mail/authinfo.db file.

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

Restart Sendmail:

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.

Use the mailx command to send a test message to a real email account you use every day.

mailx your_real_email_address@example.com

When prompted, enter test or whatever you want for a subject, and then press ENTER.

Subject: test

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 ENTER again.

test

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.

.
EOT

Next, run the the following command to check that the mail queue is empty and that our message has been sent.

mailq

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 freebsd@example.com.

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. [208.43.76.147], dsn=2.0.0, stat=Sent (Delivery in progress)

Make sure you can spot these messages in the log output below.

Mail Log
Feb 11 04:09:13 your_server sm-mta[49080]: 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[49079]: t1B49CZ4049079: to=your_real_email_address@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[49082]: 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[49082]: t1B49CW0049080: to=<your_real_email_address@example.com>, ctladdr=<freebsd@your_server> (1001/1001), delay=00:00:00, xdelay=00:00:00, mailer=relay, pri=30331, relay=smtp.sendgrid.net. [208.43.76.147], 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.

Conclusion

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.

6 Comments

Creative Commons License