_____________________________ / ____ / / / / .' __ \ /__./ / / / .' \ | ________ / / | | (_/ | ________ /_____ _____ ____ __ _____ _____ ____ _____ / \ `.__.'\ ________ /| | _ | | | | | | | \| __| / `.___ .' _____ / | | | | |- -| |__| | | | | | | | __| /____________________________/ |_|_|_|__|__|____|_____|_|___|_____|____/|_____| 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: Protocol: IMAPS (Implicit SSL/TLS encryption, not STARTTLS) port 993 Username: Password: Outgoing mail ------------- Server: Protocol: SMTPS (Implicit SSL/TLS encryption, not STARTTLS) port 465 Username: 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//* ------------------------- 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.