summaryrefslogtreecommitdiff
path: root/content/mail
diff options
context:
space:
mode:
authorTheSiahxyz <164138827+TheSiahxyz@users.noreply.github.com>2025-07-01 17:01:45 +0900
committerTheSiahxyz <164138827+TheSiahxyz@users.noreply.github.com>2025-07-01 17:01:45 +0900
commit516f632b84bc418486538a2183564fe94b89097e (patch)
tree56fed110e820d6520b39e550ccca31f00cae33ff /content/mail
init
Diffstat (limited to 'content/mail')
-rw-r--r--content/mail/inbox.md214
-rw-r--r--content/mail/rdns.md36
-rw-r--r--content/mail/security.md72
-rw-r--r--content/mail/smtp.md74
-rw-r--r--content/mail/validate.md230
5 files changed, 626 insertions, 0 deletions
diff --git a/content/mail/inbox.md b/content/mail/inbox.md
new file mode 100644
index 0000000..3f70b9c
--- /dev/null
+++ b/content/mail/inbox.md
@@ -0,0 +1,214 @@
+---
+title: "Setting up an E-mail Inbox"
+tags: ['mail']
+date: 2022-12-04
+---
+In the article on [SMTP and Postfix](/mail/smtp), we set up a simple
+Postfix server that we could use to programatically send mail with the
+`mail` command. In order to have a true and fully-functional mail
+server, users should be able to login to a mail client where they
+can read their inbox and send mail remotely. In order to achieve this we need Dovecot,
+which can store mails received by the server,
+authenticate user accounts and interact with mail.
+
+If we're setting up an inbox we will also want spam detection software, such
+as spam assassin.
+
+## Dovecot and Spamassassin
+
+ apt install dovecot-imapd dovecot-sieve spamassassin spamc
+
+Unblock the imap port:
+
+ ufw allow 993
+
+## Certificate
+
+We will want a SSL certificate for the `mail.` subdomain. We can get
+this with [Certbot](/basic/certbot/). Assuming we are using Nginx for our
+server otherwise, run:
+
+ certbot --nginx certonly -d mail.example.org
+
+## DNS
+
+We also need two little DNS records set on your domain registrar's site/DNS server:
+
+1. An MX record. Just put your domain, **example.org**, in the "Points to" field.
+2. A CNAME record. Host field: **mail.example.org**. "Points to" field: **example.org.**
+
+## Configuring Dovecot
+
+Dovecot\'s configuration file is in `/etc/dovecot/dovecot.conf`. If you
+open that file, you will see this line: `!include conf.d/*.conf` which adds
+all the `.conf` files in `/etc/dovecot/conf.d/` to the Dovecot
+configuration.
+
+One can edit each of these files individually to get the needed
+configuration, but to make things easy here, delete or backup the main
+configuration file and we will replace it with one single config file
+with all important settings in it. Make sure you change `ssl_cert`
+and `ssl_key` accordingly.
+
+``` wide
+# Note that in the dovecot conf, you can use:
+# %u for username
+# %n for the name in name@domain.tld
+# %d for the domain
+# %h the user's home directory
+
+# Connections between the mail client and Dovecot needs to be encrypted
+ssl = required
+ssl_cert = </etc/letsencrypt/live/mail.example.org/fullchain.pem
+ssl_key = </etc/letsencrypt/live/mail.example.org/privkey.pem
+ssl_min_protocol = TLSv1.2
+ssl_cipher_list = EECDH+ECDSA+AESGCM:EECDH+aRSA+AESGCM:EECDH+ECDSA+SHA256:EECDH+aRSA+SHA256:EECDH+ECDSA+SHA384:EECDH+ECDSA+SHA256:EECDH+aRSA+SHA384:EDH+aRSA+AESGCM:EDH+aRSA+SHA256:EDH+aRSA:EECDH:!aNULL:!eNULL:!MEDIUM:!LOW:!3DES:!MD5:!EXP:!PSK:!SRP:!DSS:!RC4:!SEED
+ssl_prefer_server_ciphers = yes
+ssl_dh = </usr/share/dovecot/dh.pem
+auth_mechanisms = plain login
+auth_username_format = %n
+
+protocols = $protocols imap
+
+# Search for valid users in /etc/passwd
+userdb {
+ driver = passwd
+}
+#Fallback: Use plain old PAM to find user passwords
+passdb {
+ driver = pam
+}
+
+# Our mail for each user will be in ~/Mail, and the inbox will be ~/Mail/Inbox
+mail_location = maildir:~/Mail:INBOX=~/Mail/Inbox:LAYOUT=fs
+namespace inbox {
+ inbox = yes
+ mailbox Drafts {
+ special_use = \Drafts
+ auto = subscribe
+}
+ mailbox Junk {
+ special_use = \Junk
+ auto = subscribe
+ autoexpunge = 30d
+}
+ mailbox Sent {
+ special_use = \Sent
+ auto = subscribe
+}
+ mailbox Trash {
+ special_use = \Trash
+}
+ mailbox Archive {
+ special_use = \Archive
+}
+}
+
+# Here we let Postfix use Dovecot's authetication system.
+service auth {
+ unix_listener /var/spool/postfix/private/auth {
+ mode = 0660
+ user = postfix
+ group = postfix
+}
+}
+
+protocol lda {
+ mail_plugins = $mail_plugins sieve
+}
+protocol lmtp {
+ mail_plugins = $mail_plugins sieve
+}
+plugin {
+ sieve = ~/.dovecot.sieve
+ sieve_default = /var/lib/dovecot/sieve/default.sieve
+ sieve_dir = ~/.sieve
+ sieve_global_dir = /var/lib/dovecot/sieve/
+}
+```
+
+### Settings Explained
+
+Take a good look at the above settings to understand what\'s going on. Some of
+the settings include:
+
+1. SSL settings to allow encrypted connections.
+2. The mail server will authenticate users against PAM/passwd, which
+ means users you create on the server (so long as they are part of
+ the `mail` group) will be able to receive and send mail.
+3. Default directories for a mail account: Inbox, Sent, Drafts, Junk,
+ Trash and Archive.
+4. Create a `unix_listener` that will allow Postfix to authenticate
+ users via Dovecot.
+5. Setup the Dovecot sieve plugin, which provides mail filtering facilities
+ at time of final message delivery. Sieve scripts can be used to
+ customize how messages are delivered, whether they're forwarded
+ or stored in special folders.
+
+Next, we can tell sieve to automatically move mail flagged as spam to
+the junk folder:
+
+ echo "require [\"fileinto\", \"mailbox\"];
+ if header :contains \"X-Spam-Flag\" \"YES\"
+ {
+ fileinto \"Junk\";
+ }" > /var/lib/dovecot/sieve/default.sieve
+
+After that, we should create the `vmail` user and group, which will
+access the mails, and then update the sieve configuration:
+
+ grep -q '^vmail:' /etc/passwd || useradd vmail
+ chown -R vmail:vmail /var/lib/dovecot
+ sievec /var/lib/dovecot/sieve/default.sieve
+
+Then, enable pam authentication for Dovecot:
+
+ echo "auth required pam_unix.so nullok
+ account required pam_unix.so" >> /etc/pam.d/dovecot
+
+## Connecting Postfix and Dovecot
+
+We need to tell Postfix to look to Dovecot for authenticating users/passwords.
+Dovecot will be putting an authentication socket in `/var/spool/postfix/private/auth`.
+
+ postconf -e 'smtpd_sasl_auth_enable = yes'
+ postconf -e 'smtpd_sasl_type = dovecot'
+ postconf -e 'smtpd_sasl_path = private/auth'
+ postconf -e 'mailbox_command = /usr/lib/dovecot/deliver'
+
+## Connecting Postfix and Spamassassin
+
+We will change `/etc/postifx/master.cf` so postfix can route mail through spamassassin. First
+we can cleanup the default configuration. Feel free to make a backup.
+
+ sed -i '/^\s*-o/d;/^\s*submission/d;/^\s*smtp/d' /etc/postfix/master.cf
+
+Finally, run this command to finish the configuration for spamassassin.
+
+ echo "smtp unix - - n - - smtp
+ smtp inet n - y - - smtpd
+ -o content_filter=spamassassin
+ submission inet n - y - - smtpd
+ -o syslog_name=postfix/submission
+ -o smtpd_tls_security_level=encrypt
+ -o smtpd_sasl_auth_enable=yes
+ -o smtpd_tls_auth_only=yes
+ smtps inet n - y - - smtpd
+ -o syslog_name=postfix/smtps
+ -o smtpd_tls_wrappermode=yes
+ -o smtpd_sasl_auth_enable=yes
+ spamassassin unix - n n - - pipe
+ user=debian-spamd argv=/usr/bin/spamc -f -e /usr/sbin/sendmail -oi -f \${sender} \${recipient}" >> /etc/postfix/master.cf
+
+## Make new mail accounts
+
+This is the easy part. Let's say we want to add a user Billy and let him
+receive mail, run this:
+
+ useradd -m -G mail billy
+ passwd billy
+
+Any user added to the `mail` group will be able to receive mail. Suppose a user
+Cassie already exists and we want to let her receive mail too. Just run:
+
+ usermod -a -G mail cassie
diff --git a/content/mail/rdns.md b/content/mail/rdns.md
new file mode 100644
index 0000000..85cce0f
--- /dev/null
+++ b/content/mail/rdns.md
@@ -0,0 +1,36 @@
+---
+title: "Setup rDNS"
+tags: ['mail']
+date: 2022-12-02
+---
+
+While [DNS records](/basic/dns) refer a domain name to the IP address
+where the the website is hosted, there is also rDNS (reverse DNS) and
+specifically PTR (pointer) records which do the reverse: link a
+server\'s IP to a domain name.
+
+This is important for many things, but especially email. Many email
+servers require that other servers that send them mail have PTR records
+to prevent spam.
+
+## Setting your PTR Record
+
+DNS settings are set with your registrar, while rDNS settings are set
+with your server or VPS provider. **Remember to set records for both
+IPv4 and IPv6!**
+
+In [Vultr](https://www.vultr.com/?ref=8384069-6G) we want to set the
+IPv4 record, click on the server, then \"Settings,\" and make sure the
+\"IPv4\" tab is selected. We can then edit the \"Reverse DNS\" blank
+shown below.
+
+{{< img alt="IPv4 rDNS PTR record set in Vultr" src="/pix/rdns-01.png" >}}
+
+The setting for IPv6 is obviosuly under the IPv6 tab. Note here that we
+copy the full IPv6 address from above and create a new rDNS entry by
+pasting that and the domain name in the blanks below. Then just select
+\"Add.\"
+
+{{< img alt="IPv6 rDNS PTR record set in Vultr" src="/pix/rdns-02.png" >}}
+
+That\'s it!
diff --git a/content/mail/security.md b/content/mail/security.md
new file mode 100644
index 0000000..4527b34
--- /dev/null
+++ b/content/mail/security.md
@@ -0,0 +1,72 @@
+---
+title: "Harden your E-mail Server"
+tags: ["mail"]
+date: 2022-12-05
+---
+
+## Hardening Postfix
+
+Put restrictions on servers sending mail to you.
+
+ postconf -e 'smtpd_recipient_restrictions = permit_sasl_authenticated, permit_mynetworks, reject_unauth_destination, reject_unknown_recipient_domain'
+
+## Anonymize Headers
+
+Use some regular expressions to prevent some meta data like a client's ip address
+from being leaked.
+
+ echo "/^Received:.*/ IGNORE
+ /^X-Originating-IP:/ IGNORE
+ /^User-Agent:/ IGNORE
+ /^X-Mailer:/ IGNORE" >> /etc/postfix/header_checks
+
+Add this file to the postfix configuration:
+
+ postconf -e "header_checks = regexp:/etc/postfix/header_checks"
+
+## Fail2Ban
+
+If you're not familiar with fail2Ban, it's essentially a program which
+blocks bot's and hacker's login requests after a few invalid attempts.
+
+ apt-get install fail2ban
+
+Make a local copy of the configuration file:
+
+ cp /etc/fail2ban/jail.conf /etc/fail2ban/jail.local
+
+Go down to the `# Mail servers` line and paste this:
+
+ [postfix]
+
+ enabled = true
+ port = smtp,ssmtp,submission
+ filter = postfix
+ logpath = %(postfix_log)s
+ backend = systemd
+
+
+ [sasl]
+
+ enabled = true
+ port = smtp,ssmtp,submission,imap2,imap3,imaps,pop3,pop3s
+ filter = postfix[mode=auth]
+ # You might consider monitoring /var/log/mail.warn instead if you are
+ # running postfix since it would provide the same log lines at the
+ # "warn" level but overall at the smaller filesize.
+ logpath = %(postfix_log)sAdd commentMore actions
+ backend = systemd
+ maxretry = 1
+ bantime = 21600
+
+ [dovecot]
+
+ enabled = true
+ port = smtp,ssmtp,submission,imap2,imap3,imaps,pop3,pop3s
+ filter = dovecot
+ logpath = %(dovecot_log)sAdd commentMore actions
+ backend = systemd
+
+This will only grant 2 login attempts and then block the requester for 6 hours. Now restart `fail2ban`:
+
+ systemctl restart fail2ban
diff --git a/content/mail/smtp.md b/content/mail/smtp.md
new file mode 100644
index 0000000..d5c1f48
--- /dev/null
+++ b/content/mail/smtp.md
@@ -0,0 +1,74 @@
+---
+title: "Sending and Receiving Email"
+tags: ["mail"]
+date: 2022-12-01
+---
+
+The first step to setting up an email server is having an SMTP server.
+SMTP sends and receives email. Whether we want a full email server or
+just the ability to send automated email by script, we will need SMTP,
+and Postfix is the standard SMTP server.
+
+Here let\'s set a server up. Note that our goal is to be able to send
+emails from our server. If you want a full email server, this is the
+first step, and we will address the rest later.
+
+## Before beginning!
+
+Whatever VPS ([Vultr](https://www.vultr.com/?ref=8384069-6G) or
+[Frantech](https://my.frantech.ca/aff.php?aff=3886)) or IPS you are
+using, it is a very common policy to **automatically block all email
+ports by default**. VPS providers do this to prevent spammers from using
+their services.
+
+If you want to start an email server, therefore, go to your VPS\'s site
+and open a ticket or make a request to open up email ports, notably port `25`. This is a
+simple process that requires nothing too special. One of the wagies at
+your VPS will kindly do the needful and open your ports for you. Note
+that this is not the same as unblocking a port with [ufw](/../ufw),
+which still needs to be done for SMTP to work.
+
+ ufw allow 25,587 proto tcp
+
+## Installation
+
+First, we install Postfix and also `mailutils`, which comes with some
+mail programs we will use.
+
+ apt install -y mailutils postfix
+
+Installing Postfix for the first time will give us some graphical
+options.
+
+{{< img alt="SMTP Postfix internet site choice" src="/pix/smtp-01.png" link="/pix/smtp-01.png" >}}
+
+When asked for a \"mail name\", give your full domain name from which
+you would like mail to come and go, e.g. **example.org** or
+**chad.thesiah.xyz**
+
+{{< img alt="SMTP Postfix fully qualified domain name" src="/pix/smtp-02.png" link="/pix/smtp-02.png" >}}
+
+## Test the email
+
+That is actually all you need to have set up to have a barebones,
+send-only email server. We can test our server by running a `mail`
+command like that below.
+
+ echo "Hi there.
+
+ This is the text." | mail -s "Email from the server" your@emailaddress.com
+
+This type of command is sufficient enough for your server to send mail.
+Note that we use the `-s` option to specify the email\'s subject while
+we pipe the email content into the `mail` command via standard input. In
+this example I use a quoted multiline email as an example.
+
+## Do you see your message?
+
+If you sent the above test message to an account on Gmail or another
+major email provider, there is **very high** chance of the message you
+sent above being marked as spam or not appearing at all!
+
+Don\'t worry, we\'ll take care of that in the next two articles where we
+set up rDNS with your VPS provider and various other DNS
+records to validate the emails you send.
diff --git a/content/mail/validate.md b/content/mail/validate.md
new file mode 100644
index 0000000..8447409
--- /dev/null
+++ b/content/mail/validate.md
@@ -0,0 +1,230 @@
+---
+title: "Validate Email with DNS Records"
+tags: ['mail']
+date: 2022-12-03
+---
+Email is a lot like real-life mail. You can send email to anyone, but
+you can also write whatever return address you\'d like. That is, it\'s
+pretty easy to pretend to be someone else via mail, and that was
+originally the case with email as well: email is just text, and you
+could just change your `From:` address to any email address you wanted!
+DKIM (Domain Keys Identified Mail) helps solve this issue.
+
+OpenDKIM will generate a public/private cryptographic key pair for your
+server. The public key will be made available publicly in your server\'s
+DNS records and the private key will be used to sign every single email
+that leaves the server. This means that people receiving mail from your
+server can now be absolutely sure that it originated from your server
+because their servers can check the cryptographic signature on the email
+with the public key!
+
+OpenDKIM ensures that email originated from the server it claims it did,
+but it does not ensure that it originated from the user account it
+claims it did. This easier problem is solved by server-side
+authorization settings.
+
+## Installation
+
+```sh
+apt install opendkim opendkim-tools
+```
+
+## The Keys and Files
+
+We have to generate the DKIM keys and create some secondary files that
+will be required for our configuration.
+
+### Generate the DKIM key
+
+<!--
+TODO: Make a unique directory for each domain to later allow multiple domain
+DKIM validation for servers serving more than one domain name.
+-->
+
+Here we create directories for the OpenDKIM keys, generate them, and
+ensure they have the right file permissions.
+
+```sh
+mkdir -p /etc/postfix/dkim
+opendkim-genkey -D /etc/postfix/dkim/ -d example.org -s mail
+chgrp opendkim /etc/postfix/dkim/*
+chmod g+r /etc/postfix/dkim/*
+```
+
+### Create the key table
+
+Now we\'ll tell OpenDKIM where the newly generated keys are on the file
+system.
+
+```sh
+echo "mail._domainkey.example.org example.org:mail:/etc/postfix/dkim/mail.private" > /etc/postfix/dkim/keytable
+```
+
+### Create the signing table
+
+```sh
+echo "*@example.org mail._domainkey.example.org" > /etc/postfix/dkim/signingtable
+```
+
+### Adding trusted hosts
+
+```sh
+echo "127.0.0.1
+10.1.0.0/16
+1.2.3.4/24" > /etc/postfix/dkim/trustedhosts
+```
+
+## Configuring opendkim.conf
+
+Now we have all the raw material, so open up `/etc/opendkim.conf` and we
+can finalize our server settings. First, add these lines that will
+source the files we just created.
+
+```yaml
+KeyTable file:/etc/postfix/dkim/keytable
+SigningTable refile:/etc/postfix/dkim/signingtable
+InternalHosts refile:/etc/postfix/dkim/trustedhosts
+
+Canonicalization relaxed/simple
+Socket inet:12301@localhost
+```
+
+There will already be an uncommented `Socket` directive, so delete,
+comment out or replace it with the above.
+
+## Interfacing with Postfix
+
+There are a couple things we must add to the Postfix SMTP server
+settings to interface it with OpenDKIM. Specifically, we have to set our
+OpenDKIM server, which will be running on port `12301`, as a milter
+(mail filter). This is easy to do with the four commands below:
+
+```sh
+postconf -e "myhostname = $(cat /etc/mailname)"
+postconf -e "milter_default_action = accept"
+postconf -e "milter_protocol = 6"
+postconf -e "smtpd_milters = inet:localhost:12301"
+postconf -e "non_smtpd_milters = inet:localhost:12301"
+```
+
+## Restart and reload Postfix and DKIM
+
+Now that we have all our settings in place:
+
+```sh
+systemctl restart opendkim
+systemctl enable opendkim
+systemctl reload postfix
+```
+
+## Adding the DNS record!
+
+We are only one step away from having functioning OpenDKIM. We must add the
+DKIM public key to our server\'s DNS settings, so go ahead and open up your
+registrar\'s site or wherever your site\'s DNS settings are.
+
+The public key is found in the file `/etc/postfix/dkim/mail.txt`, but it
+will display as multiple lines and multiple quoted strings, which is
+annoying and hard to copy-and-paste into your registrar. To make things
+easier, run the following command to format the key in the way we need
+it for the DNS TXT entry:
+
+```sh
+echo -e "
+
+v=DKIM1; k=rsa; $(tr -d "
+" </etc/postfix/dkim/mail.txt | sed "s/k=rsa.* \"p=/k=rsa; p=/;s/\"\s*\"//;s/\"\s*).*//" | grep -o "p=.*")
+
+"
+```
+
+Take the very long output of that command, which will start with
+`v=DKIM1` and add it as a TXT entry in your DNS settings as below. The
+host we put it for is `mail._domainkey`.
+
+{{< img alt="Adding the OpenDKIM TXT entry in DNS settings" src="/pix/dkim-01.png" link="/pix/dkim-01.png" >}}
+
+On my registrar, this is how it is input, but on some registrars, it may be
+required to include your domain name as well as `mail._domainkey.example.org`.
+
+If you have your own DNS server, add a TXT entry as follows:
+
+```txt
+mail._domainkey.example.org TXT v=DKIM1; k=rsa; p=ThatLongRandomSequenceOfLettersAndNumbersOfYours
+```
+
+## Testing it out!
+
+Now we want to send an email to make sure that your emails will now be
+signed with OpenDKIM.
+
+### Hostname
+
+If you\'ve followed these instructions, all emails from the domain
+**example.org** will now have a DKIM signature on them. If we send mail
+via the `mail` command, however, their domain of origin will be whatever
+your server\'s hostname is, which you may have set to something
+different than your domain.
+
+You can permanently change your hostname by changing it in
+`/etc/hostname` and rebooting, or you can just run
+`hostname example.org` to change it temporarily for testing. Either way,
+this will allow us to run the `mail` command as in [the SMTP
+article](../smtp).
+
+```sh
+echo "Hi there.
+
+This is the text." | mail -s "Email from the server" your@emailaddress.com
+```
+
+### More helpful troubleshooting.
+
+You can also go to [this site](https://appmaildev.com/en/dkim), which
+will help you troubleshoot any other DKIM problems if you mistyped
+something.
+
+## DMARC
+
+DMARC (Domain-based Message Authentication Protocol) is a protocol designed
+to give email domain owners the ability to protect their domain from
+unauthorized use.
+
+Add the dmarc user:
+
+ useradd -m -G mail dmarc
+
+Open up your registrar or DNS settings again, and make a new TXT record like
+we did with DKIM, except now use the output from the following command:
+
+ echo "_dmarc.$(cat /etc/mailname)"
+ echo "v=DMARC1; p=reject; rua=mailto:dmarc@$(cat /etc/mailname); fo=1"
+
+The first line is the Host field. The latter is the TXT value.
+
+### Sender Policy Framework
+
+Saving the easiest for last, we should add a TXT record for SPF,
+an email-authentication standard used to prevent spammers from sending messages
+that appear to come from a spoofed domain.
+
+ cat /etc/mailname
+ IP4=<your VPS's IPv4 address>
+ IP6=<your VPS's IPv6 address>
+ echo "v=spf1 mx a:mail.$(cat /etc/mailname) ip4:$IP4 ip6:$IP6 -all"
+
+**Note**: previous versions of this guide didn't ask you to specify the `ip4`
+and `ip6` mechanisms. If you don't include them, some email hosts (most
+notoriously gmail) will not accept mail from your server.
+
+The `IP4` and `IP6` values should be the same as what you set your [PTR
+records](../rdns) to.
+
+The output of `cat /etc/mailname` is the Host field. The output of the second command is the TXT value.
+
+Again, you can check [that site](https://appmaildev.com/en/spf)
+to make sure your DKIM, DMARC, and SPF entries are valid. That's it!
+
+## Contribution
+
+- SPF mechanisms updated by Martin Chrzanowski \-- [website](https://m-chrzan.xyz), [donate](https://m-chrzan.xyz/donate.html)