_____________________________
/ ____ / / /
/ .' __ \ /__./ /
/ / .' \ | ________ /
/ | | (_/ | ________ /_____ _____ ____ __ _____ _____ ____ _____
/ \ `.__.'\ ________ /| | _ | | | | | | | \| __|
/ `.___ .' _____ / | | | | |- -| |__| | | | | | | | __|
/____________________________/ |_|_|_|__|__|____|_____|_|___|_____|____/|_____|
Mailnode is a dockerized email service that supports virtual inboxes, virtual
mail domains, address aliases, a mailing list service, and is compatible with
the DNS-based message authentication schemes SPF, DKIM, and DMARC.
Mailnode runs solely on well-established free software components. Mailnode's
daemons and required default port numbers are listed below. Due to the
prevalence of email spam, it is important to ensure that email ports are not
blocked or filtered by your hosting provider / ISP.
Service Description TCP ports
-------------------------------------------------------------
postfix Mail transfer agent 25, 465
dovecot Mail delivery agent 993
mlmmj Mailing list manager -
opendkim Message auth mail filter -
nginx-proxy (*) Reverse proxy / TLS helper 80, 443
* Nginx-proxy (with acme-companion) is an extra dependency which is required to
obtain and manage TLS certificates for the mail server. The proxy service is
used so that mailnode doesn't require exclusive control over the web ports.
docker-compose.yml contains the integrations with nginx-proxy.
Prerequisites
=============
1) Forward DNS host record(s) for mail server: Create an A record and/or
AAAA record pointed at the mail server IP address.
2) Reverse DNS record(s): Create PTR records for the server's IPv4 and, if
necessary, IPv6 addresses. You may need to ask your hosting provider to
do this for you.
3) Unblock your ports: If any of the above TCP ports are blocked (either
inbound or outbound) by your upstream provider, submit a support ticket
to have them opened. Otherwise, seek another service provider.
Mailnode makes no official recommendation regarding ISP or hosting
providers.
4) Run nginx-proxy: Clone docker compose files from the "proxy-docker" git
repository and launch the reverse-proxy with ACME companion service.
`docker compose --file ./docker-compose-acme.yml up --detach`
Configuration
=============
docker-compose.yml
------------------
There are a couple variables in this file that must be filled in with
information about your server. Eg: the server hostname and a list of valid
"local" mail domains. Look for comments that say "# CONFIGURE ME!"
Virtual domains must be comma separated. An example value for this field
might be: "foo.com,baz.bar.net" in order to accept mail for addresses like
"user@foo.com" and "user@baz.bar.net" respectively.
userconfig/passwd
-----------------
This is the master user/inbox database for the Mailnode instance. It is in
the format of a standard system passwd file - fields are separated by colons,
and comments and blank lines are not allowed. The format for each line of
this file is:
USERNAME:PASSWORDHASH:UID:GID::::
Username must be the user's full email address. This is because Mailnode
supports multiple receiving domains.
A Password hash can be generated using the `makepasswd.sh` script. Hashes
are given a unique salt. Therefore, even if two users will use the same
password, it is wise to assign them independent hashes. This way, someone
reading the passwd file will be unable to determine which passwords match,
if any.
UID and GID refer to the underlying unix account which actually owns the
stored mail files. These must be the constant value `2000`. The final few
fields are not used at the moment.
The default file contains a dummy user record to show an example, this line
should be removed when adding real users.
userconfig/aliases
------------------
This file defines email address alias lists. Each line contains the name of
an alias, followed by one or more addresses that the alias will forward to.
Forwarding addresses can be of different domains than the alias address.
They can even reside at domains not managed by the Mailnode instance.
Unlike the passwd file, blank lines and comment lines (`#`) are allowed.
This example forwards both "webmaster" and "postmaster" addresses to a
generic "admin" address, and delivers all mail to admin to two real human
beings:
webmaster@site.com admin@site.com
postmaster@site.com admin@site.com
admin@site.com alice@site.com bob@site.com
Installation
============
After making modifications to the config files, use docker compose to start
Mailnode or update an existing instance. When building and starting Mailnode
for the first time, it is recommended to direct output to a log file so you can
easily grab the DKIM key that is generated for your server. This public key
will be needed for a DNS record later.
docker compose up --detach --build | tee log.txt
The DKIM key generated by the build process is persisted by a named volume.
This allows the image to be rebuilt without requiring the need to rotate keys.
Final DNS Records
=================
After setting up Mailnode, some additional DNS entries are required in order to
properly federate with other mail servers. Add them to your domain's zone file.
(domain.com => your domain name, mail.domain.com => mail server hostname)
domain.com MX 10 mail.domain.com
domain.com TXT "v=spf1 mx -all"
default._domainkey.domain.com TXT "v=DKIM1; h=sha256; k=rsa; p=MIGfMA0GCSqGSIb3D....."
_dmarc.domain.com TXT "v=DMARC1; p=none; rua=mailto:postmaster@domain.com"
MX (Mail exchange)
------------------
This is a standard DNS record that instructs external senders which server(s)
to direct your incoming mail to. The given record directs all mail to
`mail.domain.com:25`. 10 is a priority value, which is meaningful if
multiple MX entries are present.
The remaining records pertain to message sender authentication and apply to
your outgoing mail.
SPF (Sender policy framework)
-----------------------------
An SPF record states which internet hosts are permitted to send mail on
behalf of your domain. The given record permits all your domain's mail
exchangers (aka: any host referred to by an MX record) and hard-fails all
others. For more information on SPF records, see:
http://www.open-spf.org/SPF_Record_Syntax/
DKIM (DomainKeys identified mail)
---------------------------------
DKIM uses asymmetric cryptography to sign outgoing mail, proving that each
message originates from one of your domain's approved mail servers. DKIM
signatures include a key selector field - this enables you to publish many
public keys in your domain. Mailnode uses only a single key pair, with the
selector name "default". Key selectors are part of the DNS entry name, as
seen above. The body of the TXT record contains all the crypto parameters
for the public key.
To find your DKIM record value, refer to the output of the docker image
build log. After opendkim generated an initial key pair, the data for the
public key DNS record is echoed to the console.
DMARC (Domain-based message authentication, reporting, and conformance)
-----------------------------------------------------------------------
DMARC instructs a message receiver what to do if a message from your domain
fails either of the SPF or DKIM checks. Note that implementing DMARC may be
optional for your site.
The given record specifies a policy of "none", which effectively allows the
delivery of unauthenticated messages. Alternatives are "quarantine" (spam
folder) and "reject" (return error code during SMTP). The "rua" tag
specifies an email address to deliver aggregate DMARC reports to. If your
"postmaster" mailbox is not setup, change this value or remove the tag.
For more information on DMARC records, see:
https://mxtoolbox.com/dmarc/details/what-is-a-dmarc-record
Login to Mailboxes
==================
Connect to Mailnode with any normal email client using the information below.
Incoming mail
-------------
Server: <your mail server hostname>
Protocol: IMAPS (Implicit SSL/TLS encryption, not STARTTLS) port 993
Username: <user's email address>
Password: <user's plaintext password>
Outgoing mail
-------------
Server: <your mail server hostname>
Protocol: SMTPS (Implicit SSL/TLS encryption, not STARTTLS) port 465
Username: <user's email address>
Password: <user's plaintext password>
Note that new accounts initially only have an INBOX folder where new messages
are delivered. Message archival, saving sent messages, or message drafts must
be handled by clients.
The "From:" header used in outgoing messages is managed by clients - users
configure their "real names" locally instead of on the server. However the
return path ("envelope sender", etc) must match the user's email address,
otherwise the message will be rejected.
Mailing Lists
=============
Mailnode hosts configurable mailing lists using the Mlmmj mailing list manager.
Basic usage is explained here, although it is a good idea to familiarize
yourself with the underlying system: https://mlmmj.org/
Mlmmj uses a directory for each mailing list to record its configuration and
metadata. This includes things like the message archive, list of subscribers,
message queues, and configuration parameters. In particular, there are two
subdirectories of interest: (1) "control", which contains list configuration
options and (2) "text", which contains message templates to use when delivering
automated responses to users.
Under Mailnode, each list's main metadata directory is managed for you. You
Only need to manually configure "control" and "text" content in directories
under `userconfig/`.
userconfig/lists/<NAME>/*
-------------------------
Create subdirectories under `userconfig/lists/` for each of your desired
mailing lists. The directory name is used to identify the list, and the
directory contents are the files which would reside in the list's "control"
(configuration options) directory.
The `makelist.sh` script can be used to automatically create a mailing list
using some recommended sane default settings. Keep in mind that the list's
post address will really be the only user-facing identifier for the list.
The owner email address will be used as the initial list owner and moderator.
Emails sent to `listname+owner@domain.com` will be delivered to this person.
For a fuller description of the available configuration settings, see the
Mlmmj documentation: https://mlmmj.org/TUNABLES.html
Be careful when removing a list directory! Whenever Mailnode is restarted
(rebuilt) after removing lists, the list's real metadata directory will be
purged from the system. This includes all subscribers and the full message
archive as well!
userconfig/listtext/*
---------------------
This directory contains the "text" auto mail templates that are shared by
all configured mailing lists. You shouldn't need to change anything, but if
you wish to customize any messages, this is the place to do it.
After creating lists, rebuild and restart Mailnode. The mailing lists are
interacted with by sending an email to one of several "request" email addresses.
Assuming a mailing list whose post address is "mylist@domain.com", the following
basic actions are possible:
mylist@domain.com Deliver message to all list subscribers
mylist+owner@domain.com Deliver message to the list owner(s)
mylist+help@domain.com Retrieve a summary of list information
mylist+subscribe@domain.com Subscribe to receive all list messages (*)
mylist+subscribe-digest@domain.com Subscribe to receive list digests (*)
mylist+unsubscribe@domain.com Unsubscribe from all list messages (*)
For all "request" addresses ("mylist+xxx@domain.com"), the message subject and
body are ignored.
* Subscribe and unsubscribe requests require reply to a confirmation message to
prevent abuse.
Mailing List Archives
=====================
Some web frontends exist for Mlmmj to allow searching and browsing message
archives. However, I personally don't like any of the user interfaces available.
At the moment, Mailnode does not expose any message archive interface.
Implementing one is left as a TODO for a future release.
Testing and Troubleshooting
===========================
For help validating your mail setup, check out these tools that will test your
DNS records, message signatures, and deliverability.
https://intodns.com/ Validate domain DNS records
https://appmaildev.com/en/dkim Test SPF, DKIM, and DMARC via email
https://mxtoolbox.com/blacklists.aspx Check blacklists for server IP
https://mxtoolbox.com/SuperTool.aspx MXToolBox super tool
Your mail server's IP address may appear on various block lists if it was
recently used to send email spam. Residential and many VPS IP blocks are also
sometimes listed. If you appear on a blocklist, you will likely have a very
hard time getting your mail accepted by major email providers such as Microsoft,
Google, and Yahoo, etc. Blacklist maintainers will usually provide a process
for getting your IP delisted. Initiate these procedures at your own discretion.
In addition to the above tools, you can send mail to one of the auto-responders
below. A reply should be returned shortly containing your original message along
with all of the header changes that were made in transit. This will allow you
to test DKIM functionality along with two-way message deliverability.
sa-test@sendmail.net
check-auth@verifier.port25.com
autorespond+dkim@dk.elandsys.com
dktest@exhalus.net
dkim-test@altn.com
dktest@blackops.org
Look for the message headers "DKIM-Signature:" and "Authentication-Results:" to
have been added. Authentication results injected by the remote system should
indicate a PASS. Otherwise, there is a misconfiguration, or something along the
way altered the email to invalidate the signature.
The auto-responder's reply mail will also be DKIM-signed. If you inspect the
reply's actual headers you should see authentication results injected by your
own server. This should also give a PASS.