Sending emails from an IPv6-only host


I have a cheap IPv6-only VPS which hosts a website using CloudFlare’s reverse proxy providing IPv4 connectivity. The VPS also has IPv4 connectivity through a public NAT64 service, which uses a NAT gateway to send packets to an IPv4 destination by embedding the IPv4 address in the v6 address. But sending emails is another ball game.

I can’t send emails directly from the host as most email providers do not have IPv6 connectivity right now. Another option is an SMTP relay like Mailgun, but again their SMTP server (or the gateway to it) is not dual-stack. Another option is to use Google’s SMTP server to send out emails, but not only do you have to create a somewhat insecure app password bypassing the usual two-factor authentication, it is also known to be somewhat unreliable - sometimes emails being forwarded hours after it was received.

Herein comes an SMTP smarthost. If you have an SMTP server running on a dual stack machine, it can receive mail forwarded from your IPv6-only server, and deliver it to both IPv6 and IPv4 recipients.

The eventual setup turned out to be pretty simple even though I had initially complicated it by using a manualrouter. Turns out configuring the local Exim4 application as a satellite does the exact same thing.

For the purposes of this guide, let’s assume the hostname of the IPv6 only host to be ipv6only.myv6domain.com having the address 8f8a:e9be:a00b::7dcb:56bb:b6b0:11c6 and the dual-stack hostname to be dual.mydualdomain.com having the address 4644:16b2:b52b:448f:1346::d6c8:920a. These are randomly generated addresses, so don’t start getting any smart ideas. This guide also assumes that the email is being sent with a From: <something@myv6domain.com> field.

On the IPv6-only host, configure Exim4 to act as a satellite, which only forwards mail another SMTP server. This can be done with the dpkg-reconfigure exim4-config for a step-by-step wizard guided process, or by editing the file directly. The contents of the resulting config file at /etc/exim4/update-exim4.conf.conf is as follows. I have preserved the comments at the top for the sake of making it less confusing.

# Please note that this is _not_ a dpkg-conffile and that automatic changes
# to this file might happen. The code handling this will honor your local
# changes, so this is usually fine, but will break local schemes that mess
# around with multiple versions of the file.
#
# update-exim4.conf uses this file to determine variable values to generate
# exim configuration macros for the configuration file.
#
# Most settings found in here do have corresponding questions in the
# Debconf configuration, but not all of them.
#
# This is a Debian specific file

dc_eximconfig_configtype='satellite'
dc_other_hostnames='ipv6only.myv6domain.com'
dc_local_interfaces='127.0.0.1 ; ::1'
dc_readhost='myv6domain.com'
dc_relay_domains=''
dc_minimaldns='false'
dc_relay_nets=''
dc_smarthost='[4644::16b2::b52b::448f::1346::::d6c8::920a]::5483'
CFILEMODE='644'
dc_use_split_config='false'
dc_hide_mailname='true'
dc_mailname_in_oh='true'
dc_localdelivery='mail_spool'

The important config options here are the dc_eximconfig_configtype denoting the SMTP server as being a satellite, the dc_other_hostnames having the FQDN hostname of the current server, the dc_readhost having only the domain part of the hostname, and the dc_smarthost having the IPv6 address of the dual-stack server. Note that every single colon is doubled in the address, because of having to escape it. Exim uses the “:” as a separator in its config literals. Another option is changing the separator character, but I opted to escape the colon for the sake of simplicity and readability. Note that it also has a non-standard port defined alongside the IPv6 address.

Restart the Exim4 instance using service exim4 restart.

Now, onto the configuration at the dual-stack server. First, we need to make Exim4 listen on that non-standard port. Update /etc/default/exim4 to have SMTPLISTENEROPTIONS look like this -

SMTPLISTENEROPTIONS='-oX 5483 -oP /run/exim4/exim.pid'

Next, we make sure that Exim4 isn’t binding only to the localhost IPv4 and IPv6 addresses only. By default, it does not listen to any external interfaces. Make sure the dc_local_interfaces line in /etc/exim4/update-exim4.conf.conf looks like this -

dc_local_interfaces='127.0.0.1 ; ::1 ; 4644:16b2:b52b:448f:1346::d6c8:920a'

The IPv6 address at the end is the address of the network interface with external IPv6 connectivity. You will need to change this to match yours. Also note that this doesn’t require escaping the colons as it seems to use semicolons as the separator between addresses.

You also need to make sure that you allow emails to be relayed from your IPv6-only host. In the same file, make sure dc_relay_nets looks like this -

dc_relay_nets='8f8a::e9be::a00b::::7dcb::56bb::b6b0::11c6/128

Note that this option requires escaping the colons. Don’t ask me why. I did not make the rules. I tried it without escaping it and the server refused to accept mail from the IPv6-only host. (I know, I know, I could have read the Exim4 manual too, but where’s the fun in that?)

Note that, for me, this Exim4 instance was configured as internet - with the description text in the wizard being internet site; mail is sent and received directly using SMTP. I did not re-run the wizard as it was already configured previously, but you can choose to run dpkg-reconfigure exim4-config instead of editing the file. The whole file looked like this -

# /etc/exim4/update-exim4.conf.conf
#
# Edit this file and /etc/mailname by hand and execute update-exim4.conf
# yourself or use 'dpkg-reconfigure exim4-config'
#
# Please note that this is _not_ a dpkg-conffile and that automatic changes
# to this file might happen. The code handling this will honor your local
# changes, so this is usually fine, but will break local schemes that mess
# around with multiple versions of the file.
#
# update-exim4.conf uses this file to determine variable values to generate
# exim configuration macros for the configuration file.
#
# Most settings found in here do have corresponding questions in the
# Debconf configuration, but not all of them.
#
# This is a Debian specific file

dc_eximconfig_configtype='internet'
dc_other_hostnames='dual.mydualdomain.com'
dc_local_interfaces='127.0.0.1 ; ::1 ; 4644:16b2:b52b:448f:1346::d6c8:920a'
dc_readhost=''
dc_relay_domains=''
dc_minimaldns='false'
dc_relay_nets='8f8a::e9be::a00b::::7dcb::56bb::b6b0::11c6/128'
dc_smarthost=''
CFILEMODE='644'
dc_use_split_config='false'
dc_hide_mailname=''
dc_mailname_in_oh='true'
dc_localdelivery='maildir_home'

Restart the Exim4 instance using service exim4 restart.

Now the two Exim4 instances are set to talk to each other, but we need to make sure the firewall will let connections from the IPv6-only instance through. I use UFW.

ufw allow from 8f8a::e9be::a00b::::7dcb::56bb::b6b0::11c6 proto tcp to any port 5483 comment "Allow email forwards from ipv6only.myv6domain.com"

Now everything is set up in terms of configuration. All that is left is troubleshooting. Let’s send a test email from the IPv6-only server. This will provide a verbose output on the console, but also make sure you are monitoring the Exim mainlog on both the servers at the same time using something like tail -f /var/log/exim4/mainlog

exim -v -i -t <<'EOF'
From: test@myv6domain.com
To: soumik@soumikghosh.com
Subject: Exim Command Line Test

Hello, this is a test email sent via Exim.
EOF

If everything is done correctly, you should see your email arriving in your inbox or your spam folder. If it doesn’t, it’s time for troubleshooting. A few Exim queue management commands which really helped in this regard were -

exim -bp
exiqgrep -xi | xargs exim -Mrm
exiqgrep -zi | xargs exim -Mrm

The first one shows the messages in the queue. The second one clears out non-frozen emails from the queue and the third one frozen emails. Exim freezes out messages that it couldn’t deliver after a few retries or when delivery fails completely.

Note that successful email delivery requires the correct setup of SPF, DKIM and optionally, DMARC for reporting. It is not in the scope of this article to help set those up, but a minimal SPF setup for the IPv6-only domain (myv6domain.com) should at least allow the dual-stack host to send emails on its behalf.

"v=spf1 a:dual.mydualdomain.com ~all"

This authorises the A and AAAA records of dual.mydualdomain.com to send emails from <something@myv6domain.com>.