Use Postfix to get email from your Fedora system

Communication is key. Your computer might be trying to tell you something important. But if your mail transport agent (MTA) isn’t properly configured, you might not be getting the notifications. Postfix is a MTA that’s easy to configure and known for a strong security record. Follow these steps to ensure that email notifications sent from local services will get routed to your internet email account through the Postfix MTA.

Install packages

Use dnf to install the required packages (you configured sudo, right?):

$ sudo -i
# dnf install postfix mailx

If you previously had a different MTA configured, you may need to set Postfix to be the system default. Use the alternatives command to set your system default MTA:

$ sudo alternatives --config mta
There are 2 programs which provide 'mta'. Selection Command
*+ 1 /usr/sbin/sendmail.sendmail 2 /usr/sbin/sendmail.postfix
Enter to keep the current selection[+], or type selection number: 2

Create a password_maps file

You will need to create a Postfix lookup table entry containing the email address and password of the account that you want to use to for sending email:

# MY_EMAIL_PASSWORD=abcdefghijklmnop
# echo "[$MY_SMTP_SERVER]:$MY_SMTP_SERVER_PORT $MY_EMAIL_ADDRESS:$MY_EMAIL_PASSWORD" >> /etc/postfix/password_maps
# chmod 600 /etc/postfix/password_maps
# history -c

If you are using a Gmail account, you’ll need to configure an “app password” for Postfix, rather than using your gmail password. See “Sign in using App Passwords” for instructions on configuring an app password.

Next, you must run the postmap command against the Postfix lookup table to create or update the hashed version of the file that Postfix actually uses:

# postmap /etc/postfix/password_maps

The hashed version will have the same file name but it will be suffixed with .db.

Update the file

Update Postfix’s configuration file to reference the Postfix lookup table you just created. Edit the file and add these lines.

relayhost =
smtp_tls_security_level = verify
smtp_tls_mandatory_ciphers = high
smtp_tls_verify_cert_match = hostname
smtp_sasl_auth_enable = yes
smtp_sasl_security_options = noanonymous
smtp_sasl_password_maps = hash:/etc/postfix/password_maps

The example assumes you’re using Gmail for the relayhost setting, but you can substitute the correct hostname and port for the mail host to which your system should hand off mail for sending.

For the most up-to-date details about the above configuration options, see the man page:

$ man postconf.5

Enable, start, and test Postfix

After you have updated the file, enable and start the Postfix service:

# systemctl enable --now postfix.service

You can then exit your sudo session as root using the exit command or Ctrl+D. You should now be able to test your configuration with the mail command:

$ echo 'It worked!' | mail -s "Test: $(date)"

Update services

If you have services like logwatch, mdadm, fail2ban, apcupsd or certwatch installed, you can now update their configurations so that their email notifications will go to your internet email address.

Optionally, you may want to configure all email that is sent to your local system’s root account to go to your internet email address. Add this line to the /etc/aliases file on your system (you’ll need to use sudo to edit this file, or switch to the root account first):


Now run this command to re-read the aliases:

# newaliases
  • TIP: If you are using Gmail, you can add an alpha-numeric mark between your username and the @ symbol as demonstrated above to make it easier to identify and filter the email that you will receive from your computer(s).


View the mail queue:

$ mailq

Clear all email from the queues:

# postsuper -d ALL

Filter the configuration settings for interesting values:

$ postconf | grep "^relayhost\|^smtp_"

View the postfix/smtp logs:

$ journalctl --no-pager -t postfix/smtp

Reload postfix after making configuration changes:

$ systemctl reload postfix

Photo by Sharon McCutcheon on Unsplash.


Decentralize common Fedora apps with Cjdns

Are you worried about a few huge corporations controlling the web? Don’t like censorship on centralized social media sites like facebook and twitter? You need to decentralize! The internet was designed to be decentralized. Many common activities, from social media to email to voice calls, don’t actually require a centralized service.

The basic requirement for any peer to peer application is that the peers be able to reach each other. This is impossible today for most people using IP4 behind NAT (as with most household routers). The IP4 address space was exhausted over a decade ago. Most people are in “IP4 NAT Jail.”

Your device is assigned a private IP, and translated to the public IP by the router. Without port forwarding to a specific private IP, incoming TCP connections or UDP sessions can’t tell where to forward to, and are dropped. As a result, nothing can connect to your device. You must connect to various public servers to do anything. IP4 NAT Jail forces centralization.

The simplest solution to this problem is IPv6. However, most US consumer internet providers do not offer usable IPv6. For instance, if the IPv6 prefix changes every few days, the devices are not addressable except via a dynamic DNS server. Furthermore, on a mobile device like a laptop, most WiFi does not offer IPv6 either. So you can’t use Mobile IP6 to have a stable address.

You can work around this using a VPN like OpenVPN (included in Fedora) to a centralized server with a public IP4 — perhaps one you provide yourself by renting a Virtual Personal Server. But then packets to and from your device have to travel to and from the VPN server first. You can also use a tunnel broker like

If you and your peers already have stable IPv6 addresses, you can use these for the sample applications to be showcased. But most people need to use something else.

DNS is also essentially a centrally controlled service, so this article’s two sample applications avoid the use of DNS.  Email and SIP applications have built-in address books that work just as well.  Think of your stable IPv6 address as a “phone number.”

IPv6 Overlay Mesh VPN with Cjdns

The Cjdns package (included in Fedora) implements a global IPv6 mesh by connecting to several peers instead of a centralized server. Each node has a public/private key pair. The IPv6 is the truncated SHA512 hash of the public key, preventing spoofing.

  • Packets are end to end encrypted — relays can be untrusted.
  • Packets are source routed, allowing seamless upgrades of and experimentation with routing algorithms.  (This is safe thanks to anti-spoofing.)
  • The data for routing comes from a Distributed Hash Table listing the peers of each node.
  • Peers can be explicitly configured as UDP tunnels, or auto-configured on ethernet via layer 2 protocol 0xfc00.

With Cjdns installed, you have a stable, “unspoofable” (standard cryptographic caveats apply) IPv6 address that can be used with any IPv6 ready application. Your recipient must also use the Cjdns protocol, but this isn’t much of an obstacle since it’s easier to install Cjdns than convince US ISPs to provide usable IPv6.

Install Cjdns

To install and enable the Cjdns service persistently, run these commands:

$ sudo dnf install cjdns cjdns-tools cjdns-selinux $ sudo systemctl enable --now cjdns
$ peerStats 18:03:14:56:c2:1e v20.0000.0000.0000.0019.681v1s7k3af1q2cf09txpw309zdf4q0mn7mtq0wr544dz98stwr0.k ESTABLISHED in 6kb/s out 15kb/s LOS 8 "outer"

This generates a /etc/cjdroute.conf file, pre-populated with random keys and passwords. If there’s already a Cjdns node on your LAN as above, you’re done. But more likely, there was no output from peerStats. In that case you now need to configure one or more UDP tunnels. First, you must discover the random UDP port used.

$ sudo grep bind /etc/cjdroute.conf // Port to bind the admin RPC server to. "bind": "", "bind": "", "bind": "[::]:26041", // Alternatively bind to just one device "bind": "all",

In this example, the random UDP port is 26041 for both IPv6 and IPv4. Your port will be different. Allow incoming sessions for this port.

$ sudo firewall-cmd --zone=public --add-port=26041/udp success $ sudo firewall-cmd --runtime-to-permanent success

Now you need to edit the config to add a peer. Hopefully, you are somewhat familiar with configs using JSON syntax. You must add an entry for a UDP peer using your favorite text editor, such as vim. Here is one provided on a VPS. Search for IPv4, and add the indicated stanza after connectTo, inside the braces:

$ sudo vim /etc/cjdroute.conf "": { "login": "fedora", "password":"zvkxv604fqx0zn9trhw5hjxwp3u4v2u", "publicKey":"lhj54c2xnczfurpw42d0h1bvc4qquclb4dw72q50tc83ucmm9zt0.k", "peerName":"" },

For the changes to take effect, restart cjdns.

$ sudo systemctl restart cjdns $ peerStats v20.0000.0000.0000.0017.lhj54c2xnczfurpw42d0h1bvc4qquclb4dw72q50tc83ucmm9zt0.k ESTABLISHED in 0kb/s out 0kb/s "" $ ping PING (fceb:7fc0:c62c:9cd9:2971:e3ff:aee2:6e08)) 56 data bytes 64 bytes from (fceb:7fc0:c62c:9cd9:2971:e3ff:aee2:6e08): icmp_seq=1 ttl=42 time=87.6 ms

You can now ping any node in the global IPv6 mesh. CAUTION: All those nodes can now directly connect to your device. The default Fedora firewall will block all incoming connections be default — but be careful what you allow in. Be sure to consult the package README for additional security notes.

The fedora password to this nyc VPS may not be up indefinitely, so you need some more peers. Consult a list of public peers or peer with your Fedora friends.

Decentralize Email applications

You can decentralize almost any email client included in Fedora that supports IPv6, such as alpine or Thunderbird. This example uses mailx, a bare bones CLI mail client designed for teletypes. This makes configuration and use easy to show.

Similarly, you can use any of the MTAs supplied with Fedora, but this example uses opensmtpd, as it is simple, small, and secure. By default, opensmtpd stores incoming email in /var/spool/mail, which is perfect for personal decentralized use. You can, of course, use any mail store and client you prefer.

$ sudo dnf install mailx opensmtpd $ cat >~/.mailrc <<EOF set from="mylogin@[IPv6:fc02:fefe:dead:beef:cafe:babe:1234:5678] (Real Name)" set smtp=localhost EOF

Of course, you need to use your own local login, IPv6 and name.

To receive email, you will need to edit the opensmtpd config in /etc/opensmtpd/smtpd.conf. Here is a sample. (Note this article may wrap some of the “preformatted” lines, so use your head):

# This is the smtpd server system-wide configuration file. # See smtpd.conf(5) for more information. # To accept external mail, replace with: listen on all listen on fc02:fefe:dead:beef:cafe:babe:1234:5678 hostname "[IPv6:fc02:fefe:dead:beef:cafe:babe:1234:5678]" listen on localhost # If you edit the file, you have to run "smtpctl update table aliases" table aliases file:/etc/aliases # Uncomment the following to accept external mail for domain "" #accept from any for domain "" alias deliver to mbox accept from any for domain "[IPv6:fc02:fefe:dead:beef:cafe:babe:1234:5678]" alias deliver to mbox accept for local alias deliver to mbox accept for any relay hostname "[IPv6:fc02:fefe:dead:beef:cafe:babe:1234:5678]" 

Use your actual Cjdns IP, of course. When the opensmtpd config is ready, start it so you can receive emails. If your recipient is offline, opensmtpd stores your letter and retries periodically.

$ sudo systemctl enable --now opensmtpd $ sudo firewall-cmd --zone=public --add-service=smtp $ sudo firewall-cmd --runtime-to-permanent

Now send the author a dex (decentralized) email:

$ mailx -s "Fedora Article" \ "stuart@[IPv6:fcbc:b27:be6f:94dd:4225:792:c988:8ace]" <<EOF > Great article! > EOF

That sends an email to the author’s nyc vps — so don’t be surprised if you get a reply!

Alpine is a full featured console email client. After you install and run it the first time, you can decentralize it by editing ~/.pinerc and changing these basic config items:

# Sets domain part of From: and local addresses in outgoing. user-domain=[IPv6:fc02:fefe:dead:beef:cafe:babe:1234:5678] # List of SMTP servers for sending mail. smtp-server=localhost

Decentralize SIP applications

Linphone call screen

Linphone call screen

Using Cjdns for your voice calls gives you privacy and authentication. You can use any sip client that supports IP6. This example uses the linphone app included in Fedora.

$ sudo dnf install linphone $ sudo firewall-cmd --zone=public --add-service=sip --add-port=7078/udp --add-port=9078/udp $ sudo firewall-cmd --runtime-to-permanent
Linphone network config screen

Linphone network config screen

Run linphone on your desktop, and skip the account wizard. You don’t need logins and accounts with peer to peer. Select Options, Preferences and select Use IPv6 instead of IPv4 and Direct connection to internet. Enter your Cjdns IPv6 in Public IP address. Now select Options, Quit to completely exit linphone.

The version in Fedora doesn’t provide a way to configure your peer to peer contact, so you need to edit the config file. Find the [sip] section and change guess_hostname and contact:

$ vim ~/.linphonerc guess_hostname=0 contact="Real Name" <sip:mylogin@[fc02:fefe:dead:beef:cafe:babe:1234:5678]>

Now start linphone again, and add a Fedora friend with Cjdns to the addressbook using the same address syntax. Try a text message first, then give them a call.

Of course, there are many potential issues with audio and video in a VoIP app, which are not covered here. Usually, however, linphone just works. If you don’t have any friends, you can reach out to the author via dex email at the nyc node above.