We all love the rich features, familiar interface, and rock-solid reliability of personal email services like Gmail and Yahoo. However, when you are building a brand or running a small business, sending emails from a generic @gmail.com address lacks that critical professional edge. While premium suites like Google Workspace offer custom domain integration, the per-user monthly subscription fees can quickly add up—especially for startups or small operations trying to keep overhead low.
Fortunately, there is a clever, cost-effective alternative: an Email Forwarder. Unlike a full-fledged mail server, an email forwarder does not store any messages on your server. It simply acts as a fast, lightweight traffic controller—catching incoming mail sent to your custom domain and instantly rerouting it to your existing personal inbox. Because it requires virtually zero local storage, you can run it on a microscopic budget. In this comprehensive guide, we will walk you through setting up a production-ready email forwarder on Ubuntu 24.04 and connecting it seamlessly to your personal Gmail account.
Note: It is assumed that you are setting this up in fresh install.
Prerequisites
Before we dive into the terminal, ensure you have the following components ready to go. Because email infrastructure requires strict network compliance, having these set up correctly from the start is non-negotiable.
- A VPS or Dedicated Server: A clean, fresh install of Ubuntu 24.04 LTS with a public static IP address.
- Unrestricted Mail Ports: Your hosting provider must allow unrestricted traffic on Port 25 (SMTP) and Port 587 (Submission).
- A Registered Domain Name: A domain you fully own (e.g., yourdomain.com) with access to its DNS management console (to configure routing and security records later).
A Note on Infrastructure Blockades & Port 25: Many popular cloud VPS providers (such as DigitalOcean, AWS, and Vultr) as well as traditional Internet Service Providers (ISPs) block outbound traffic on Port 25 by default to prevent spam. If Port 25 is blocked, your mail forwarder will cheerfully accept incoming emails but will completely fail to push them out to external systems like Gmail. Before proceeding, make sure your ports are open, request your cloud provider to unblock SMTP traffic, or contact your ISP to see if they can lift the restriction on your business line.
1.0 Initial Setup
1.1 Hostname Configuration
Postfix uses our server's hostname by default to identify itself when communicating with other MTAs. Hostname can have two forms:
- A Single Word: (e.g., myubuntu) Typically used for local personal computers or local network identification.
- An FQDN (Fully Qualified Domain Name): (e.g., mail.yourdomain.com) The absolute, complete domain address pointing to a specific machine on the public internet.
While a single word works fine inside a private network, internet-facing mail servers strictly require an FQDN. When your server forwards an email to an upstream provider like Yahoo or Gmail, the receiving server checks your SMTP banner identity. If your server introduces itself with a single word instead of a verified FQDN, your emails will be flagged as high-risk and outright rejected.
First, verify your current hostname:
Then change the hostname using the following command(change the placeholder value with your actual hostname):
sudo hostnamectl set-hostname mail.yourdomain.com
Next, ensure your local system can resolve this name cleanly by adding it to your local hosts file:
Add a line mapping your static public IP address to your new FQDN right below the localhost entries:
your_public_IP mail.yourdomain.com
Save and exit (Ctrl+O, Enter, Ctrl+X). You can verify everything is tracking perfectly by running hostname -f, which should print your complete FQDN back to the terminal.
1.2 DNS Configuration
A Record
This record maps your public IP with the FQDN. This is required when obtaining SSL certificate.
mail.yourdomain.com <IP-address>
MX Record
This record tells other MTAs that your mail server mail.yourdomain.com is responsible for email delivery for your domain name.
MX record @ mail.yourdomain.com
2.0 Postfix Installation & Configuration
To accept incoming messages from the public internet and route them back out to external providers, our server needs a Mail Transfer Agent (MTA). For this guide, we will use Postfix—the industry-standard, lightweight, and highly secure MTA champion for Linux environments.
Before installing any new packages, it is a crucial best practice on a fresh OS install to ensure all existing system repositories and packages are completely up to date.
sudo apt update && sudo apt upgrade -y
Once the update completes, use the following command to install Postfix.
sudo apt install postfix -y
During the installation process, your terminal will freeze and open a colorful, interactive configuration menu. Use your Tab and Enter keys to navigate through these two critical prompts:
General type of mail configuration: Select Internet Site. This setting configures Postfix to send and receive email directly using SMTP.
System mail name: Enter your base custom domain name (e.g., yourdomain.com). Do not include www. or a subdomain prefix like mail.. This acts as the default domain for emails generated natively by the server.
After the installation check the status of the Postfix using:
sudo systemctl status postfix
Now that the baseline installation is out of the way, we need to alter its default parameters to define your server's identity and, most importantly, instruct Postfix to act as a virtual forwarder rather than a traditional storage destination.
Open the primary configuration file /etc/postfix/main.cf using nano:
sudo nano /etc/postfix/main.cf
Inside the /etc/postfix/main.cf file, scroll through or append the following core parameters.
Note: Update or add the following lines, replacing yourdomain.com and mail.yourdomain.com with your actual domain and FQDN.
# Host and site name configuration
myhostname = mail.yourdomain.com
mydomain = yourdomain.com
Then add the following to at the end of the file
# Virtual alias routing configuration
virtual_alias_domains = yourdomain.com
virtual_alias_maps = hash:/etc/postfix/virtual
To understand exactly how this modifies your mail infrastructure, here is a breakdown of the variables you just set:
- myhostname: The Fully Qualified Domain Name (FQDN) of your mail server. This is the exact name the server will use to introduce itself to other servers during the SMTP handshake.
- mydomain: The parent domain name that your email server handles.
- virtual_alias_domains: This tells Postfix that it is responsible for accepting emails sent to @yourdomain.com. However, because it is specified as a virtual alias domain, Postfix knows not to look for local Linux system accounts to deliver these emails to.
- virtual_alias_maps: This points to a lookup table database file (/etc/postfix/virtual). This file acts as the directory map that tells Postfix exactly which custom domain incoming email address should be redirected to which external personal inbox (like Gmail).
Save and exit the file when finished (Ctrl+O, Enter, Ctrl+X).
With Postfix configured to look for virtual aliases, it is time to build our routing directory. This file maps your professional, custom-domain email addresses to your actual, everyday personal inbox. Create and open the virtual configuration file using nano:
sudo nano /etc/postfix/virtual
Add your forwarding rules into this file. Each mapping requires a single line, specifying the destination address separated by a space or a tab. Use the following format:
# Forwarding mapping: one from-to address pair per line.
# Format: <forward-from-addr> <whitespace> <forward-to-addr>
john@yourdomain.com mrtechsparrow123@gmail.com
support@yourdomain.com mrtechsparrow-admin@gmail.com
And for some reason, if you want to catch every single email sent to your domain that doesn't have a specific rule, add the following rule use the @ symbol followed by your domain name, with no username in front of it at the end of the file:
#The Catch-All Fallback (Processed Last)
@yourdomain.com mrtechsparrow123@gmail.com
Postfix is smart enough to evaluate specific matches first. If an incoming email does not match any explicitly named user (like john@ or support@), it will automatically fall back to the catch-all directive.
Warning: While a catch-all is incredibly convenient for catching typos, it is a massive double-edged sword. Spammers frequently use scripts to blast emails to random prefixes at custom domains (e.g., info@, sales@, hr@, invoice@, asdf123@).
With a catch-all active, your Postfix server will blindly accept all of this garbage mail and attempt to forward it to your personal Gmail account. When Gmail notices your server forwarding a massive wave of spam, it will penalize your server's public IP address. This can destroy your email deliverability, landing your legitimate forwarded emails straight into the spam folder. Use catch-alls with extreme caution!
Save and exit the file. Even though we added the mapping to the file /etc/postfix/virtual, for performance reasons Postfix does not read raw text files on the fly when processing mail. Instead, it looks for a fast, indexed binary database version of this file (virtual.db).
Whenever you create or modify your email mappings, you must explicitly compile the text file into a Postfix database using the postmap command:
sudo postmap /etc/postfix/virtual
3.0 Secure SMTP Authentication
To ensure your email forwarder isn't hijacked by spammers as an open relay, you must enforce mandatory authentication for anyone attempting to send mail through it. We will use the standard Cyrus SASL framework linked directly to Linux's system user database (PAM).
Install the required modules using:
sudo apt-get install sasl2-bin libsasl2-modules
Open /etc/default/saslauthd and ensure the mechanism is set to use the system's PAM architecture, and enable the daemon to start automatically:
sudo nano /etc/default/saslauthd
Look for the following parameters, and add them if they don't exist.
START=yes
MECHANISM="pam"
Save and exit the file. Now we are going to tell Postfix to check incoming connections against saslauthd using modern, secure mechanisms instead of looking up a separate database file. Create or edit /etc/postfix/sasl/smtpd.conf with following parameters:
sudo nano /etc/postfix/sasl/smtpd.conf
pwcheck_method: saslauthd
mech_list: PLAIN LOGIN
Save and close the file. Postfix runs in a chroot environment for security. Therefore we need to add it to the sasl group so it can communicate with the authentication daemon:
sudo adduser postfix sasl
sudo systemctl restart saslauthd postfix
Now that we have configured the authentication mechanisms, we need a dedicated, locked-down Linux user specifically for this task. Since this user only exists to authenticate for sending emails—and should never be allowed to log into our server's command line via SSH—we create it as a "system account" with no login shell. (Replace mailuser with any username you prefer)
sudo useradd -r -s /usr/sbin/nologin mailuser
- -r: Creates a system user (no home directory is made).
- -s /usr/sbin/nologin: Blocks the user from ever logging into a terminal session.
Now, set the password of the user, using:
4.0 Install SSL Certificate
When connecting your mail forwarder to major external services like Gmail or Yahoo, your server must use transport layer encryption (TLS). Even if you were connecting a traditional email client like Thunderbird to a private server, running an unencrypted connection leaves your mail sessions exposed to credential harvesting and data interception.
Furthermore, strict security providers like Gmail completely reject self-signed SSL certificates. To pass their security checks, your certificate must be issued by a recognized, public Certificate Authority (CA). Fortunately, we can use Let's Encrypt, a free, automated, and open certificate authority.
To handle the automated issuance and renewal of our Let's Encrypt certificates, we will use a tool called Certbot. Install it along with its system dependencies using the package manager:
sudo apt install certbot -y
Since this server is running exclusively as a mail forwarder and does not have an active web server (like Nginx or Apache) occupying port 80, we will tell Certbot to run in standalone mode. This temporarily spins up a microscopic web server on port 80 just long enough to verify your domain ownership with Let's Encrypt.
Note: Ensure your firewall temporarily allows incoming traffic on Port 80 before running this command, and verify that your FQDN (e.g., mail.yourdomain.com) is correctly pointing to your server's public IP via an A Record in your DNS dashboard.
Run the following command to request your certificate:
sudo certbot certonly --standalone \
-d mail.yourdomain.com \
--email your-email@gmail.com \
--agree-tos \
--no-eff-email
- --email your-email@gmail.com: Registers the certificate to your email address so Let's Encrypt can send you automated alerts if your certificate is ever nearing its 90-day expiration window.
- --agree-tos: Automatically accepts the Let's Encrypt Subscriber Agreement, saving you a manual keystroke.
- --no-eff-email: Tells Certbot not to share your email address with the Electronic Frontier Foundation (EFF) for their promotional newsletters, keeping your inbox clean.
Once successful, Certbot will save your cryptographic keys in the following directory: /etc/letsencrypt/live/mail.yourdomain.com/
Now that you have acquired a legitimate, publicly trusted certificate, you must explicitly instruct Postfix to use it for securing incoming and outgoing traffic. Open your primary Postfix configuration file again:
sudo nano /etc/postfix/main.cf
Look for the default # TLS parameters section. Locate the following lines and either remove or comment them out using a # symbol to purge the default self-signed configurations:
smtpd_tls_cert_file=/etc/ssl/certs/ssl-cert-snakeoil.pem
smtpd_tls_key_file=/etc/ssl/private/ssl-cert-snakeoil.key
smtpd_tls_security_level=may
smtp_tls_CApath=/etc/ssl/certs
smtp_tls_security_level=may
smtp_tls_session_cache_database = btree:${data_directory}/smtp_scachethen add the following parameters under that section(be sure to replace mail.yourdomain.com with your actual hostname/sub domain):
# Enable TLS Encryption when Postfix receives incoming emails (Daemon)
smtpd_tls_cert_file = /etc/letsencrypt/live/mail.yourdomain.com/fullchain.pem
smtpd_tls_key_file = /etc/letsencrypt/live/mail.yourdomain.com/privkey.pem
smtpd_tls_security_level = may
smtpd_tls_loglevel = 1
smtpd_tls_session_cache_database = btree:${data_directory}/smtpd_scache
# Enable TLS Encryption when Postfix sends outgoing emails (Client)
smtp_tls_security_level = may
smtp_tls_loglevel = 1
smtp_tls_session_cache_database = btree:${data_directory}/smtp_scache
# Enforce Modern Protocols (Disable legacy SSLv2, SSLv3, TLSv1, and TLSv1.1)
smtpd_tls_mandatory_protocols = !SSLv2, !SSLv3, !TLSv1, !TLSv1.1
smtpd_tls_protocols = !SSLv2, !SSLv3, !TLSv1, !TLSv1.1
smtp_tls_mandatory_protocols = !SSLv2, !SSLv3, !TLSv1, !TLSv1.1
smtp_tls_protocols = !SSLv2, !SSLv3, !TLSv1, !TLSv1.1save and close the file. Then open the file /etc/postfix/main.cf:
sudo nano /etc/postfix/master.cf
Look for the section starting with #submission. Un-comment it or append the following lines under it to securely bridge your Cyrus SASL configuration to the submission port:
submission inet n - n - - smtpd
-o syslog_name=postfix/submission
-o smtpd_tls_security_level=encrypt
-o smtpd_tls_wrappermode=no
-o smtpd_sasl_auth_enable=yes
-o smtpd_relay_restrictions=permit_sasl_authenticated,reject
-o smtpd_recipient_restrictions=permit_mynetworks,permit_sasl_authenticated,reject
This enables the submission service of Postfix so that external email clients (like Gmail or Thunderbird) can securely hand off emails to your Postfix SMTP server using your mailuser credentials.
Save and close the file, then restart Postfix to apply all changes globally:
sudo systemctl restart postfix
5.0 Setting Up SPF, DKIM, and DMARC
An encrypted connection prevents people from eavesdropping on your mail, but it doesn't prove to the world that you actually own your domain name. To prevent malicious actors from spoofing your identity, you must configure the holy trinity of email authentication: SPF, DKIM, and DMARC.
When you reply to an email from your personal Gmail app using your custom domain, the message routes through your Postfix server. The receiving server will check these three public DNS rules to verify that your server had the right to send that message.
5.1 Setting Up SPF
5.1.1 Publish SPF Record
Sender Policy Framework (SPF) is a public directory listed in your DNS configuration that explicitly names which IP addresses are authorized to send email on behalf of your domain. Log into your DNS provider's dashboard and create a new record with the following parameters:
- Type: TXT
- Host/Name: @ (or leave blank depending on your provider)
- Value/Text: v=spf1 ip4:YOUR_SERVER_IP ~all
What this means:
- v=spf1: Identifies this string as an SPF validation rule.
- ip4:YOUR_SERVER_IP: Tells receiving servers that your specific VPS IP address is an authorized sender.
- ~all: Specifies a "Soft Fail." It instructs receiving servers to accept emails originating from other IPs but mark them as suspicious, while fully trusting your server's IP.
5.1.2 Install & Configure SPF Policy Agent
While configuring an outbound SPF record protects your domain identity, we also want to protect our server from being used as a pass-through for spam. By telling Postfix to check the SPF records of incoming emails, we can drop forged or spoofed emails right at the front gate. This prevents your server from forwarding garbage to Gmail, keeping your server's IP reputation pristine.
Install the Python-based SPF policy engine from the official Ubuntu repositories:
sudo apt install postfix-policyd-spf-python
We need to tell the master Postfix process to spawn the SPF daemon when the mail system boots up. Open the master configuration file:
sudo nano /etc/postfix/master.cf
Scroll to the absolute bottom of the file and append the following lines exactly as shown.
policyd-spf unix - n n - 0 spawn
user=policyd-spf argv=/usr/bin/policyd-spfSave and close the file (Ctrl+O, Enter, Ctrl+X). Now we must tell Postfix to enforce this policy service on all incoming messages. Open the primary Postfix configuration file:
sudo nano /etc/postfix/main.cf
Scroll to the bottom of the file. If you already have an active smtpd_recipient_restrictions block, update it to match this structure. If you do not have one, append these lines to the absolute bottom of the file:
policyd-spf_time_limit = 3600
smtpd_recipient_restrictions =
permit_mynetworks,
permit_sasl_authenticated,
reject_unauth_destination,
check_policy_service unix:private/policyd-spf
Apply the changes by restarting the mail server daemon:
sudo systemctl restart postfix
5.2 Setting Up DKIM
While SPF relies on IP addresses, DKIM uses cryptographic signatures. Your server will embed a hidden, private cryptographic signature into the header of every outbound email you send. Receiving mail servers will read this signature and match it against a public key published in your DNS records to verify the email wasn't altered in transit.
5.2.1 Installation & Initial Configuration
To handle the automated cryptographic signing, we will install OpenDKIM and its management utilities:
sudo apt install opendkim opendkim-tools -y
Next, add the postfix system user to the opendkim group so that both services can safely share resources and communicate without permission blocks:
sudo gpasswd -a postfix opendkim
Open the primary configuration file:
sudo nano /etc/opendkim.conf
We need to fine-tune this file to make it resilient and verbose enough for troubleshooting. Locate the line that reads Syslog yes, and add the Logwhy directive directly beneath it to enable detailed debugging logs in /var/log/mail.log:
Next, scroll down to find the following parameters. Uncomment them (remove the #) and change the canonicalization setting from simple to relaxed/simple. This tells OpenDKIM to tolerate minor whitespace changes made to headers by intermediate servers during the forwarding process without breaking the signature:
#Canonicalization simple
#Mode sv
#SubDomains no
After uncommenting, it should look like this:
Canonicalization relaxed/simple
Mode sv
SubDomains no
Finally, scroll down toward the bottom of the file. Look for the line #ADSPAction continue (or simply go to the line right below SubDomains no) and append these performance and reliability configurations:
AutoRestart yes
AutoRestartRate 10/1M
Background yes
DNSTimeout 5
SignatureAlgorithm rsa-sha256
Scroll all the way to the absolute bottom of /etc/opendkim.conf and append the following lines to tell OpenDKIM to look for its domain maps, signing rules, and trusted hosts within external dataset tables:
# Map domains in From addresses to keys used to sign messages
KeyTable refile:/etc/opendkim/key.table
SigningTable refile:/etc/opendkim/signing.table
# Hosts to ignore when verifying signatures
ExternalIgnoreList /etc/opendkim/trusted.hosts
# A set of internal hosts whose mail should be signed
InternalHosts /etc/opendkim/trusted.hosts
Save and close the file (Ctrl+O, Enter, Ctrl+X).
5.2.2 Create Signing Table, Key Table and Trusted Hosts File
Next, create the dedicated directory structure to securely store these tables and your cryptographic keys:
sudo mkdir -p /etc/opendkim/keys
Because these directories will hold your highly sensitive private keys, modify the ownership and permissions so that only the isolated opendkim system process can read or write to them:
sudo chown -R opendkim:opendkim /etc/opendkim
sudo chmod go-rw /etc/opendkim/keys
The signing table acts as a routing map. It tells OpenDKIM: "If an outbound email's 'From' address matches this domain, sign it using this specific key selector.". Create and open the singular signing.table file using nano:
sudo nano /etc/opendkim/signing.table
Paste the following two wildcard rules into the file (be sure to replace yourdomain.com with your actual domain):
*@your-domain.com default._domainkey.your-domain.com
*@*.your-domain.com default._domainkey.your-domain.com
While the signing table defines which key identifier to use, the key table tells OpenDKIM where to physically find the cryptographic private key on your server's storage drive. Create and open the key.table file:
sudo nano /etc/opendkim/key.table
Add the following mapping string on a single line (replace yourdomain.com with your actual domain):
default._domainkey.your-domain.com your-domain.com:default:/etc/opendkim/keys/your-domain.com/default.private
Save and close the file (Ctrl+O, Enter, Ctrl+X). The trusted hosts file tells OpenDKIM who to trust blindly. If an email originates from an IP address or domain listed in this file, OpenDKIM will cryptographically sign it for outbound delivery instead of wasting time trying to verify it as an incoming external message. Create and open the trusted.hosts file:
sudo nano /etc/opendkim/trusted.hosts
Paste the following loopback loop and domain rules into the blank file:
127.0.0.1
localhost
.your-domain.com
Save and close the file.
Note: When adding your domain to the trusted.hosts file, do not use an asterisk wildcard like *.yourdomain.com. OpenDKIM handles subdomain wildcards in this specific file using only a leading dot (.yourdomain.com). Adding an asterisk will cause OpenDKIM to fail to recognize your internal infrastructure.
5.2.3 Generate Private/Public Keypair
Because OpenDKIM handles both signing outgoing messages and verifying incoming ones, it relies on an asymmetric keypair. You will generate a private key (which stays locked securely on your server to sign your outgoing mail) and a public key (which is published openly to your DNS records for the rest of the world to read and verify).
First, create a dedicated subdirectory explicitly named after your domain to store its unique keypair:
sudo mkdir /etc/opendkim/keys/your-domain.com
Next, use the opendkim-genkey utility to generate your secure, enterprise-grade keys:
sudo opendkim-genkey -b 2048 -d your-domain.com -D /etc/opendkim/keys/your-domain.com -s default -v
- -b 2048: Generates a robust 2048-bit key. Modern mail providers like Google strongly recommend 2048-bit keys, as older 1024-bit options are increasingly treated as a security risk.
- -d yourdomain.com: Tells the tool which domain name to bind to the key structure.
- -D /etc/opendkim/keys/yourdomain.com: Sets the exact folder destination where the completed keys should be written.
- -s default: Establishes your "selector" name (also known as the key's public identifier). This matches the tables we built in the previous steps.
- -v: Verbose mode, which prints out status updates to your console while the cryptographic math runs.
Once executed, this command writes two distinct files into your domain directory: default.private (your hidden signature maker) and default.txt (the public DNS map).
Your private key is incredibly sensitive; if an unauthorized actor gains access to it, they can perfectly spoof your domain and pass DKIM verification globally.
Assign absolute ownership of the private key to the opendkim system user:
sudo chown opendkim:opendkim /etc/opendkim/keys/your-domain.com/default.private
Then, strip all global permissions entirely, restricting read and write access strictly to the opendkim daemon process itself:
sudo chmod 600 /etc/opendkim/keys/your-domain.com/default.private
5.2.4 Publish DKIM Key
Now it is time to publish your public key to the world by adding a new record to your domain registrar's DNS management console. First, output the contents of the generated public key file to your terminal screen:
sudo cat /etc/opendkim/keys/your-domain.com/default.txt
The output will look something like this:
default._domainkey IN TXT ( "v=DKIM1; k=rsa; p=MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAv0..." )
To format this for your DNS provider, create a new record with these settings:
- Type: TXT
- Host/Name: default._domainkey
- Value/Text: The entire string inside the parentheses.
Note: DNS configuration tools are notoriously picky. Copy the entire value between the parentheses, paste it into a raw text editor (like Notepad), and manually strip out all internal double quotes and line-breaking whitespaces so the p= parameter is one continuous, unbroken string of text. If you leave the double quotes or spaces intact, your verification tests in the next step will almost certainly fail.
5.2.5 Testing DKIM
DNS records can take anywhere from a few minutes up to 24 hours to propagate across the internet. Once you have saved your new TXT record, you can check if your Ubuntu server can successfully pull and authenticate the public key using the built-in diagnostic utility:
sudo opendkim-testkey -d your-domain.com -s default -vvv
If everything is OK, you will see Key OK in the command output.
opendkim-testkey: using default configfile /etc/opendkim.conf
opendkim-testkey: checking key 'default._domainkey.your-domain.com'
opendkim-testkey: key secure
opendkim-testkey: key OK
Note: If your output shows key OK but mentions key not secure, your configuration is still 100% correct. The phrase "key secure" only appears if your domain registrar has active DNSSEC (DNS Security Extensions) enabled. As long as the final line explicitly reads key OK, your server is successfully talking to your DNS provider, your cryptographic signatures match perfectly, and you are officially ready to deploy!
If you see the query timed out error, you need to comment out the following line in /etc/opendkim.conf file and restart opendkim.service.
TrustAnchorFile /usr/share/dns/root.key
5.2.6 Connecting OpenDKIM with Postfix
Now we must configure Postfix and OpenDKIM to speak to one another. By default, OpenDKIM creates a traditional local Unix socket file to handle communications. However, because Postfix's core processes run inside a secure chroot jail on Ubuntu, it treats the directory /var/spool/postfix as its entire world. It cannot see the default system runtime directories. To bridge this gap, we must force OpenDKIM to place its communication socket file inside Postfix's jail environment.
Create a dedicated directory inside the Postfix spool folder to house the socket file and assign ownership to the opendkim user and link it to the postfix system group so both applications have the clearance required to read and write to the socket:
sudo mkdir /var/spool/postfix/opendkim
sudo chown opendkim:postfix /var/spool/postfix/opendkim
Open the primary OpenDKIM configuration file:
sudo nano /etc/opendkim.conf
Locate the Socket directive. Depending on your version of Ubuntu, it will look like one of the following lines:
Socket local:/run/opendkim/opendkim.sock
Replace it with the following line. (If you can’t find the above line, then add the following line.)
Socket local:/var/spool/postfix/opendkim/opendkim.sock
Save and close the file. If you can find the following line in /etc/default/opendkim file
SOCKET="local:/var/run/opendkim/opendkim.sock"
or
SOCKET=local:$RUNDIR/opendkim.sock
change it to
SOCKET="local:/var/spool/postfix/opendkim/opendkim.sock"
Save and close the file. Finally, we must instruct Postfix to route outbound mail through this new physical file path. Open your Postfix configuration:
sudo nano /etc/postfix/main.cf
Go to the bottom of the file where we defined our Milters, and change them from the network port setup to our new Unix socket path:
# Milter configuration
milter_default_action = accept
milter_protocol = 6
smtpd_milters = local:opendkim/opendkim.sock
non_smtpd_milters = $smtpd_milters
Note: Notice that we do not write out the full /var/spool/postfix/opendkim/... path inside main.cf. Because Postfix is jailed inside that folder, paths are resolved relatively. Writing local:opendkim/opendkim.sock automatically tells Postfix to look inside its jail folder.
Restart both services to initialize the new Unix socket pipeline:
sudo systemctl restart opendkim postfix
6.0 Installing & Configuring SRS (Sender Rewriting Scheme)
When an external sender (e.g., alice@yahoo.com) sends an email to your custom alias (you@your-domain.com), your server automatically processes it and forwards it directly to your personal Gmail account.
However, during this transfer, the email's underlying envelope sender address (MAIL FROM) remains alice@yahoo.com. When Google's inbound servers receive this message from your server's IP address, they look up Yahoo's public SPF records. Since your server's IP is obviously not authorized to deploy mail on behalf of Yahoo, the SPF check fails catastrophically, causing Google to flag the message as spam or reject it completely.
This is where SRS (Sender Rewriting Scheme) steps in. SRS intercepts forwarded messages and rewrites the envelope sender to use your own domain name (turning it into something like SRS0=xxxx=yahoo.com=alice@your-domain.com). Because the envelope sender now wraps back to your-domain.com, Google runs the SPF check against your SPF record and passes it with flying colors. If the email bounces, your server safely catches the bounce, decodes the SRS token, and routes the notification back to Alice automatically.
6.1 Install & Configure Postsrsd
The standard, most reliable tool to handle this rewriting process on Ubuntu is postsrsd. Install it via the package manager:
sudo apt install postsrsd -y
On Ubuntu 22.04 LTS and 24.04 LTS, PostSRSd is driven by a simple configuration file. Open it to define your server's primary handling domain:
sudo nano /etc/default/postsrsd
Locate the SRS_DOMAIN directive. It will likely be set to your local server hostname by default. Update it to point directly to your primary domain name:
SRS_DOMAIN=your-domain.com
Save and close the file (Ctrl+O, Enter, Ctrl+X).
6.2 Connect Postfix to PostSRSd
Next, we must instruct Postfix to route all inbound and outbound message envelopes through the PostSRSd process. Open the primary configuration file:
sudo nano /etc/postfix/main.cf
Scroll to the absolute bottom of the file and append the following configuration mapping block:
# Sender Rewriting Scheme (SRS) Configuration
sender_canonical_maps = tcp:127.0.0.1:10001
sender_canonical_classes = envelope_sender
recipient_canonical_maps = tcp:127.0.0.1:10002
recipient_canonical_classes = envelope_recipient
Save and close the file. Apply the new routing changes and initialize the rewriting engine by restarting both the postsrsd daemon and Postfix:
sudo systemctl restart postsrsd postfix
Ensure postsrsd is configured to start up automatically whenever your server boots up in the future:
sudo systemctl enable postsrsd
6.3 Verify That SRS is Working Correctly
Before routing live external production traffic, you can use Postfix's built-in utility postmap to query the local TCP ports to confirm that the translation engine successfully modifies incoming strings.
Run this command to test an outbound translation (simulating an email forwarding out to Gmail):
postmap -q "randomuser@gmail.com" tcp:127.0.0.1:10001
If your configuration is correct, the terminal will instantly return a hashed string resembling the following output:
SRS0=f3a7=B6=gmail.com=randomuser@your-domain.com
This confirmation proves that your rewrite pipeline is functioning exactly as intended. Any message arriving from an outside sender will now be cleanly packaged under your own domain's signature before hitting Google's gates, guaranteeing a definitive green light on all incoming SPF checks.
7.0 Connect With Gmail
With your mail server fully hardened, authenticated via SPF/DKIM, and protected against forwarding breaks via PostSRSd, you have a flawless inbound pipeline. External emails sent to you@yourdomain.com will drop straight into your regular Gmail inbox.
The final piece of the puzzle is the outbound pipeline: configuring Gmail so you can hit "Reply" or "Compose" using your custom domain identity. Gmail will securely route these outbound messages through your Ubuntu server via an encrypted TLS connection on port 587, where your server will cryptographically sign them and deliver them safely to the recipient.
Log into your personal Gmail account via a web browser, and click the Settings (Gear) Icon in the top-right corner, then select See all settings.
Navigate to the Accounts and Import tab along the top menu bar.
Locate the Send mail as: section and click on Add another email address. A yellow pop-up window will appear.
Enter your name, your domain's email address, and then uncheck the box "
Treat as an alias". Then click Next Step.
Note: If you keep this box checked, Gmail treats the custom address as your primary identity, meaning when you email yourself or reply to threads, things can loop strangely. Unchecking it tells Gmail to handle it as a completely independent, professional email account.In the next screen of the pop-up window, you will instruct Gmail how to securely hand off outbound mail to your Ubuntu infrastructure. Fill out the fields exactly as follows:
- SMTP Server: mail.yourdomain.com (Replace with your actual mail server domain name)
- Port: Choose 587 from the dropdown menu.
- Username: Enter your authenticated SASL mail user.
- Password: Enter your corresponding SASL mail password.
- Security: Select the radio button for Secured connection using TLS (recommended).
Once you click "Add Account", Gmail's servers will instantly ping your mail server on port 587, authenticate using your credentials, and send a verification email containing a numeric confirmation code to you@yourdomain.com. As your server's inbound forwarding architecture is already live, that verification email will automatically bounce through your server and land directly in your regular Gmail inbox within a few seconds.
Open your inbox, open the confirmation email from Google, and copy the numeric confirmation code. Go back to the yellow pop-up window, paste the code into the verification field, and click Verify.
Congratulations! You have successfully built a fully autonomous, enterprise-grade email forwarder on Ubuntu. You get to enjoy the sleek, unlimited interface of Gmail while maintaining absolute professional ownership and perfect cryptographic compliance over your personal domain name! If you think this was helpful to your please leave a comment and share this tutorial with your friends.
Comments
Post a Comment