Table of Contents
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.
Note: As of July 1, 2022, the cloud provider no longer supports FreeBSD Droplets through the Control Panel or API. However, you can still spin up FreeBSD Droplets using a custom image. Learn how to import a custom image to the cloud provider by following our product documentation.
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 server
- 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
nanoorvim - 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:
[secondary_label 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
[label /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
[label /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:
[secondary_label 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
[label /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
[label /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
[label /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
[label /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
[label /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.)
[label /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.
[secondary_label 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 server 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.