Setting Up SMTP Relay Using Postfix and MSMTP

1. Overview

This guide documents how I configured a Linux-based SMTP relay server to allow office copiers to send email securely through Gmail. The project solved the challenge of devices that do not support OAuth2 authentication, enabling them to send authenticated email while complying with Gmail’s security requirements.

This SMTP relay solution:

  • Authenticates outbound email via Gmail using OAuth2

  • Restricts relay access to specific copier subnets

  • Automates token management to avoid manual intervention

The relay acts as a secure bridge between legacy hardware (that can’t support modern authentication) and Gmail’s stricter authentication requirements.


2. Assumptions

This solution was designed under the following assumptions:

  • The organization uses Gmail or Google Workspace as its email provider.

  • Copiers and scanners on the network do not support OAuth2 authentication for SMTP.

  • A dedicated Linux server or virtual machine was available to serve as the SMTP relay, running Ubuntu 22.04 LTS.

  • The copier network is isolated or controlled (e.g., a trusted subnet such as 192.0.2.0/24).

  • A Google Cloud project was created with access to OAuth2 credentials (client ID, client secret) and a refresh token.

  • The relay would only send outbound email (no need to receive inbound mail).

  • All outbound email must be authenticated and delivered via Gmail’s SMTP servers.

 

3. Objectives

The primary goals of this project were:

  • Enable copiers without OAuth2 support to send email through Gmail

  • Create a secure relay server to handle email from trusted copier IPs

  • Authenticate outbound email to Gmail using OAuth2 via msmtp

  • Automate access token handling using a refresh token

  • Restrict relay access to a specific network subnet

  • Provide a maintainable, repeatable process for future devices


4. Technical Setup

This solution was implemented using a combination of Postfix and msmtp on a dedicated Linux virtual machine.

Key components:

Component Purpose
Postfix Accepts SMTP traffic from copiers and relays mail
msmtp Sends authenticated email via Gmail using OAuth2
refresh_token.sh Script to automatically refresh OAuth2 access token
Linux VM (Ubuntu) Hosts the relay server with a static IP address

5. Google Cloud Project Setup 

Since Gmail requires OAuth2 authentication for SMTP access, I needed to create a Google Cloud project to generate OAuth2 credentials and obtain a refresh token for automated authentication.

Steps to set up Google Cloud Project:

  1. Logged into Google Cloud Console.

  2. Created a new project named smtp-relay-project.

  3. Enabled the Gmail API in the project:

    • Navigated to APIs & Services → Library.

    • Searched for “Gmail API” and clicked “Enable”.

  4. Created OAuth2 credentials:

    • APIs & Services → Credentials → Create Credentials → OAuth Client ID.

    • Application Type: Web Application.

    • Gave it a name like smtp-relay-client.

    • Added http://localhost to Authorized Redirect URIs.

  5. Downloaded the client secret JSON file for later use.


6. Generating the Refresh Token

I wrote a Bash script to simplify obtaining the refresh token from Google’s OAuth2 API.

The script generates the authorization URL, prompts the user to paste in the authorization code from Google, and exchanges it for a refresh token.

Here’s the script:

#!/bin/bash

CLIENT_ID=“your-client-id.apps.googleusercontent.com”
CLIENT_SECRET=“your-client-secret”

 

REDIRECT_URI="http://localhost"

 

echo “Visit the following URL in your browser to authorize:”

echo "https://accounts.google.com/o/oauth2/v2/auth?scope=https%3A%2F%2Fmail.google.com%2F&access_type=offline&include_granted_scopes=true&response_type=code&client_id=${CLIENT_ID}&redirect_uri=${REDIRECT_URI}"
echo ""
read -p "Enter the authorization code: " AUTH_CODE
RESPONSE=$(curl -s \
--request POST \
--data "code=${AUTH_CODE}&client_id=${CLIENT_ID}&client_secret=${CLIENT_SECRET}&redirect_uri=${REDIRECT_URI}&grant_type=authorization_code" \
https://oauth2.googleapis.com/token)
echo ""
echo "Full response:"
echo "$RESPONSE"
REFRESH_TOKEN=$(echo "$RESPONSE" | jq -r '.refresh_token')
echo ""
echo "Extracted refresh token:"
echo "$REFRESH_TOKEN"

How it works:

  • Outputs an authorization URL.

  • Prompts user to visit the link, log into Google with the account that you want to send the emails from, and paste the returned code.

  • Exchanges the code for a refresh token and prints it.

I ran the script, saved the refresh token output, and used it later in the msmtp configuration.


7. Installing Postfix (Send-Only)

Installed Postfix as a send-only mail transfer agent to accept mail from copiers and hand it off to msmtp for delivery.

sudo apt install postfix

During setup:

  • Selected “Internet Site”.

  • Set mail name to exampledomain.com.

Verified /usr/sbin/sendmail points to Postfix:

ls -l /usr/sbin/sendmail

Confirmed Postfix installed and ready.

8. Installing msmtp

Installed msmtp to act as the authenticated SMTP client to Gmail:

sudo apt install msmtp

9. Configuring msmtp

Created configuration file at /usr/local/etc/msmtprc:

defaults
auth oauthbearer
tls on
tls_trust_file /etc/ssl/certs/ca-certificates.crt
logfile /var/log/msmtp.log
account gmail
host smtp.gmail.com
port 587
from copier@exampledomain.com
user copier@exampledomain.com
passwordeval /usr/local/bin/refresh_token.sh
account default : gmail

This config instructs msmtp to use Gmail SMTP with OAuth2, pulling access tokens from the refresh script.


10. OAuth2 Token Refresh Script

Created /usr/local/bin/refresh_token.sh to automatically fetch a fresh access token using the saved refresh token:

#!/bin/bash
CLIENT_ID="your-client-id.apps.googleusercontent.com"
CLIENT_SECRET="your-client-secret"
REFRESH_TOKEN="your-refresh-token"
TOKEN_URL="https://oauth2.googleapis.com/token"
ACCESS_TOKEN=$(curl -s \
 -d client_id=$CLIENT_ID \
 -d client_secret=$CLIENT_SECRET \
 -d refresh_token=$REFRESH_TOKEN \
 -d grant_type=refresh_token \
 $TOKEN_URL | jq -r '.access_token')
echo "$ACCESS_TOKEN"

Made the script executable:

chmod +x /usr/local/bin/refresh_token.sh
Tested:
/usr/local/bin/refresh_token.sh

Confirmed valid access token output.


11. msmtp Wrapper Script for Postfix

Postfix uses sendmail or a pipe command to send mail, so I created a wrapper to invoke msmtp:

sudo nano /usr/local/bin/msmtp-wrapper

Contents:

#!/bin/bash
exec /usr/bin/msmtp --file=/usr/local/etc/msmtprc -- "$@"

Made executable:

chmod +x /usr/local/bin/msmtp-wrapper

12. Configuring Postfix to Use msmtp 

Once msmtp and the wrapper script were ready, I integrated it with Postfix and secured the relay so that only authorized copier IPs could send mail through it.


Integrating msmtp into Postfix

Edited /etc/postfix/master.cf to add a custom msmtp transport:

msmtp unix - n n - - pipe
flags=F user=postfix argv=/usr/local/bin/msmtp-wrapper -t

This tells Postfix to hand off messages using the wrapper script we wrote.


Edited /etc/postfix/main.cf to activate the new transport:

default_transport = msmtp
relay_transport = msmtp

Reloaded Postfix:

sudo systemctl restart postfix

At this point, mail accepted by Postfix is passed directly to msmtp for authenticated delivery through Gmail.


13. Restricting Access to Copier Subnet

To ensure only authorized copiers could send mail, I updated the Postfix config to allow mail only from a trusted internal subnet.

In /etc/postfix/main.cf, I added:

mynetworks = 127.0.0.0/8, [::1]/128, 192.0.2.0/24
smtpd_recipient_restrictions = permit_mynetworks, reject_unauth_destination
  • mynetworks defines allowed source IPs (copier subnet).

  • smtpd_recipient_restrictions blocks all other relaying attempts.

Reloaded Postfix again:

sudo systemctl restart postfix

This ensures only devices on the copier subnet are allowed to relay messages.

14. Configuring the Copier to Use the SMTP Relay

Once the relay server was configured and secured, I updated the copier’s SMTP settings so it could send scans through the relay.


Copier SMTP Settings

On the copier’s admin interface, I configured the following:

Setting Value
SMTP Server 192.0.2.10
Port 25
SSL/TLS Disabled
Authentication None
Sender Address copier@exampledomain.com

Leave a Reply

Your email address will not be published. Required fields are marked *