Create a Send-Only SMTP Server on macOS Using Gmail

Computers sending email.

Overview

This post describes how I configured Postfix on my Mac to relay outbound email via Google's SMTP service. Why? I am creating a local website development environment where PHP applications may generate email messages for contact forms or notifications. For example, after installing WordPress, it generates an email message announcing a successful install. However, we can use the built-in mail command to run a simple test after we complete our configuration work.

This post is for those who are developers and are familiar with using the command line in a Linux-like environment. However, if something is not clear, please let me know.

I am using macOS Big Sur on my Mac. Postfix is already installed and ready to go. We only need to configure it to use Google's SMTP service. You will need to have an existing Gmail account. You will also need to set up an App password to use in your Postfix configuration. Do not use your main Gmail account password. The Gmail SMTP service is free to use for limited, personal emails. I understand that the limit is about 99 emails per day. Email from your local machine will appear to originate from your Gmail account. Setting up Postfix to relay locally originated email through your Gmail account is much simpler that trying to build a full-fledge email server. If this sounds good, then read on.

macOS Postfix SMTP Configuration for Gmail

First, we need to add the following lines to /etc/postfix/main.cf using your favorite editor and sudo:

 1$ cd /etc/postfix
 2
 3$ sudo vi main.cf
 4Password:
 5
 6$ cat main.cf
 7 o o o
 8# Define the relay host.
 9relayhost = [smtp.gmail.com]:587
10
11# Map local email (`whoami`@`hostname`) to a real email address.
12#   After creating the 'generic' file, do:
13#   sudo postmap /etc/postfix/generic
14smtp_generic_maps = hash:/etc/postfix/generic
15
16# Use TLS/SASL authentication
17smtp_sasl_auth_enable = yes
18smtp_sasl_password_maps = hash:/etc/postfix/sasl/passwd
19smtp_sasl_security_options = noanonymous
20smtp_sasl_mechanism_filter = plain
21smtp_use_tls = yes
22smtp_tls_security_level = encrypt

We need to create a couple of support files. The first one, generic, will create a mapping from our local machine account name to the Gmail account name. The second one, sasl/passwd, contains our Gmail account App password in a machine readable format.

The generic mapping file should exist already. Add lines similar (but use your actual account names) to the following at the end of the file and run postmap to generate the machine readable file, generic.db:

 1$ cd /etc/postfix
 2
 3$ sudo vi generic
 4
 5$ cat generic
 6 o o o
 7# `whoami`@`hostname`    user@gmail.com
 8
 9macuser@mymac user@gmail.com
10@mymac        user@gmail.com
11
12$ sudo postmap /etc/postfix/generic
13
14ls generic*
15generic    generic.db

You can execute:

1 
2$ echo `whoami`@`hostname`

to determine what the first mapping should be. This gives you the user at the hostname. The second mapping in the generic file is a catchall for any user on your machine. You can tweak this file as desired.

Next, we need to create the hashed passwd file. It can go anywhere; I decided to create a subdirectory, sasl, to store it in. After we create the file, we will again use postmap to create the machine readable version:

 1
 2$ sudo mkdir -p /etc/postfix/sasl
 3
 4$ cd /etc/postfix/sasl
 5
 6$ sudo vi passwd
 7
 8$ cat passwd
 9[smtp.gmail.com]:587    user@gmail.com:userapppassword
10
11$ sudo postmap passwd
12
13$ ls passwd*
14passwd    passwd.db
15
16$ sudo chmod 600 passwd*
17
18$ ls -l passwd*
19-rw------- 1 root  wheel     61 May 15 14:22 passwd
20-rw------- 1 root  wheel  16384 May 15 14:28 passwd.db

Testing our Gmail SMTP Relay Service

And that's all you have to do! The postfix service is automatically loaded by launchctl when your Mac starts up. The postfix service is not running, however, it's configured to run when it receives a request. If you are interested, have a look at:

1
2$ cat /System/Library/LaunchDaemons/com.apple.postfix.master.plist

To test your new postfix configuration, run this mail command:

1
2$ echo "This is some email." | mail -s "This is the email subject" user@example.com

While this does work, I like having the postfix service running all the time. It's helpful for debugging and checking the postfix status. Some examples for using the postfix command:

 1$ sudo postfix status
 2postfix/postfix-script: the Postfix mail system is not running
 3
 4$ sudo postfix start 
 5postfix/postfix-script: starting the Postfix mail system
 6
 7$ sudo postfix status
 8postfix/postfix-script: the Postfix mail system is running: PID: 18100
 9
10# After making any changes to the postfix configuration files ...
11$ sudo postfix reload
12postfix/postfix-script: refreshing the Postfix mail system
13
14$ mailq
15Mail queue is empty

That last command, mailq, can be used for debugging purposes. For example, if an email has not been received, you can quickly check to see if it's still queued up on your local machine.

Final Thoughts

I have created a simple solution for testing Apps that need to generate email, such as a contact form in WordPress. This is a great solution for low-volume email when testing website Apps. So far it seems to be working well for me. As always, I will try to keep this post up to date with any additional tweaks that I make.