From 343a2d8f22da424b23cd7e2e47fe9a9abcfc417f Mon Sep 17 00:00:00 2001 From: revsuine Date: Sat, 23 Nov 2024 04:02:06 +0000 Subject: [PATCH 1/8] content/blog/mail_server_alpine_postfix_dovecot_tutorial.md: stop double dkim signing --- .../blog/mail_server_alpine_postfix_dovecot_tutorial/index.md | 3 +++ 1 file changed, 3 insertions(+) diff --git a/content/blog/mail_server_alpine_postfix_dovecot_tutorial/index.md b/content/blog/mail_server_alpine_postfix_dovecot_tutorial/index.md index fe9e42e..cce1033 100644 --- a/content/blog/mail_server_alpine_postfix_dovecot_tutorial/index.md +++ b/content/blog/mail_server_alpine_postfix_dovecot_tutorial/index.md @@ -1283,6 +1283,9 @@ smtp-amavis unix - - n - 2 smtp -o smtpd_client_connection_count_limit=0 -o smtpd_client_connection_rate_limit=0 -o receive_override_options=no_header_body_checks,no_unknown_recipient_checks,no_address_mappings + # avoid double dkim signing by setting smtpd_milters to empty + # otherwise will run all milters again after amavis + -o smtpd_milters= ``` The first block tells Postfix to send emails to Amavis, and the second block tells Postfix to run an extra smtpd daemon From 19c742b0b41dde1f5ec44671e736e6413bfd68cc Mon Sep 17 00:00:00 2001 From: revsuine Date: Sat, 23 Nov 2024 20:47:15 +0000 Subject: [PATCH 2/8] content/blog/mail_server_alpine_postfix_dovecot_tutorial.md: postfix-policyd-spf-perl section --- .../index.md | 77 +++++++++++++++++++ 1 file changed, 77 insertions(+) diff --git a/content/blog/mail_server_alpine_postfix_dovecot_tutorial/index.md b/content/blog/mail_server_alpine_postfix_dovecot_tutorial/index.md index cce1033..7a67e99 100644 --- a/content/blog/mail_server_alpine_postfix_dovecot_tutorial/index.md +++ b/content/blog/mail_server_alpine_postfix_dovecot_tutorial/index.md @@ -94,10 +94,18 @@ The mail server will be composed of the following software: Mail delivery agent Dovecot + + SPF authentication + postfix-policyd-spf-perl + DKIM authentication and signing OpenDKIM + + DMARC authentication + OpenDMARC + Spam filter Amavis @@ -801,6 +809,8 @@ checks. ## Sender Policy Framework +### Set up your DNS record + Add a TXT record for your root domain with the contents `v=spf1 mx ~all`, like: ```dns @@ -863,6 +873,68 @@ Breaking down the TXT data: +### Get Postfix to validate SPF + +We're going to use a Postfix SMTPd policy server called postfix-policyd-spf-perl to check SPF of incoming emails. +postfix-policyd-spf-perl is very simple and requires almost no configuration. + +Install `postfix-policyd-spf-perl` and create a user, `policyd-spf` for it: + + # apk add postfix-policyd-spf-perl + # adduser -S -s /sbin/nologin -h /dev/null -H policyd-spf + +Explanation of `adduser` flags: + + + + + + + + + + + + + + + + + + + + + + +
OptionExplanation
-SCreate a system user
-s /sbin/nologinSet shell to /sbin/nologin so the user doesn't have a shell
-h /dev/nullSet home directory to /dev/null
-H + Don't create a home directory (if you try to create /dev/null and assign it to + policyd-spf there will be all sorts of permissions issues) +
+ +Now edit `/etc/postfix/master.cf` to tell Postfix to start up the postfix-policyd-spf-perl daemon: + +```conf +policyd-spf unix - n n - 0 spawn + user=policyd-spf argv=/usr/bin/postfix-policyd-spf-perl +``` + +Now get Postfix to use postfix-policyd-spf-perl in `/etc/postfix/main.cf` by adding the following lines: + +```conf +smtpd_recipient_restrictions = + permit_mynetworks, + reject_unauth_destination, + check_policy_service unix:private/policyd-spf +policyd-spf_time_limit = 3600 +``` + +postfix-policyd-spf-perl is now set up, and you can test it by sending yourself an email from a mainstream email +provider (which ought to have an SPF record) and checking for the presence of this header: + +``` +Received-SPF: pass (protonmail.com: Sender is authorized to use 'revsuine@protonmail.com' in 'mfrom' identity (mechanism 'include:_spf.protonmail.ch' matched)) +``` + ## DomainKeys Identified Mail ### Configure OpenDKIM @@ -1065,6 +1137,11 @@ non_smtpd_milters = $smtpd_milters This uses the Milter extension, which is something that can be used to process mail; in this case, to add headers to emails relating to DKIM. +You can, again, test this on both incoming and outgoing mail. On outgoing mail, there should be a `DKIM-Signature:` +header present. On incoming mail from domains implementing DKIM, there should be a +`Authentication-Results: master.revsuine.xyz;` header (obviously replacing `master.revsuine.xyz` with your hostname) +indicating whether or not the email has passed DKIM authentication. + ## Domain-based Message Authentication, Reporting, and Conformance ### Ensure your domains are aligned in email headers From 4d580d21e8142cc5d4764693d0a4035cecac0bc9 Mon Sep 17 00:00:00 2001 From: revsuine Date: Sat, 23 Nov 2024 23:07:02 +0000 Subject: [PATCH 3/8] content/blog/mail_server_alpine_postfix_dovecot_tutorial.md: opendmarc section --- .../index.md | 114 ++++++++++++++++++ 1 file changed, 114 insertions(+) diff --git a/content/blog/mail_server_alpine_postfix_dovecot_tutorial/index.md b/content/blog/mail_server_alpine_postfix_dovecot_tutorial/index.md index 7a67e99..6a05ccb 100644 --- a/content/blog/mail_server_alpine_postfix_dovecot_tutorial/index.md +++ b/content/blog/mail_server_alpine_postfix_dovecot_tutorial/index.md @@ -1274,6 +1274,120 @@ The `fo` tag indicates when you would like to receive reports. The options are: +### OpenDMARC + +We can use software called OpenDMARC to enforce DMARC policies for incoming mail. OpenDMARC is another milter. Let's +install it and enable its service: + + # apk add opendmarc + # rc-update add opendmarc + # rc-service opendmarc start + +Edit the OpenDMARC config at `/etc/opendmarc/opendmarc.conf`. + +Change + +```conf +AuthservID HOSTNAME +``` + +to + +```conf +AuthservID OpenDMARC +``` + +This is so that the `Authentication-Results` header from OpenDKIM authentication. This will also make it clear which +program adds which `Authentication-Results` header. + +Add the following line, replacing `mail.domain.com` with your *hostname* (so in [my +instance](#a-note-on-my-dns-records), this is `master.revsuine.xyz`). + +```conf +TrustedAuthservIDs mail.domain.com +``` + +Enable `RejectFailures`, which means your server will comply with `p=reject` in DMARC DNS records. + +```conf +RejectFailures true +``` + +You also probably want to enable `RequiredHeaders`, which rejects emails that don't conform to RFC5322 standards, e.g. +are missing a `From:` header. + +```conf +RequiredHeaders true +``` + +In case external SPF validation fails (as in, no SPF results are placed in the message header), you probably want to +add + +```conf +SPFSelfValidate true +``` + +which tells OpenDMARC to perform the SPF check itself if it can't find SPF results in the message header. + +Now provide OpenDMARC with a socket to use for communication with sendmail. We will use a TCP socket on port 8893: + +```conf +Socket inet:8893@localhost +``` + +For a Unix socket, you'd use the following format: + +```conf +Socket local:/var/run/opendmarc/opendmarc.sock +``` + +By default, you will have the line + +```conf +IgnoreHosts /etc/opendmarc/ignore.hosts +``` + +in `/etc/opendmarc/opendmarc.conf`. This tells OpenDMARC to not authenticate the list of hosts in +`/etc/opendmarc/ignore.hosts`. An example `ignore.hosts` is + + 127.0.0.1 + 93.113.25.226 + +Keep in mind that if you have specified `IgnoreHosts`, this file needs to exist in order for OpenDMARC to run. If you +have the option set, make sure to `touch /etc/opendmarc/ignore.hosts` (or whatever filepath you've specified). +Alternatively, comment out this option in order to use the default, which is to not authenticate mail coming from +127.0.0.1. + +Restart OpenDMARC for these changes to take effect: + + # rc-service opendmarc restart + +To have Postfix use the OpenDMARC milter, it's simple as adding the socket to the `smptd_milters` and +`non_smtpd_milters` variable in `/etc/postfix/main.cf`: + +```conf +milter_default_action = accept +milter_protocol = 6 +smtpd_milters = inet:127.0.0.1:8891,inet:127.0.0.1:8893 +non_smtpd_milters = $smtpd_milters +``` + +Restart Postfix for the changes to take effect: + + # rc-service postfix restart + +And when you receive emails from a legitimate source that implements DMARC, you should see the following headers in +your emails: + +``` +Received-SPF: pass (protonmail.com: Sender is authorized to use 'revsuine@protonmail.com' in 'mfrom' identity (mechanism 'include:_spf.protonmail.ch' matched)) receiver=master.revsuine.xyz; identity=mailfrom; envelope-from="revsuine@protonmail.com"; helo=mail-40130.protonmail.ch; client-ip=185.70.40.130 +DMARC-Filter: OpenDMARC Filter v1.4.2 master.revsuine.xyz 88CFF1288D1 +Authentication-Results: OpenDMARC; dmarc=pass (p=quarantine dis=none) header.from=protonmail.com +Authentication-Results: OpenDMARC; spf=pass smtp.mailfrom=protonmail.com +Authentication-Results: master.revsuine.xyz; + dkim=pass (2048-bit key; secure) header.d=protonmail.com header.i=@protonmail.com header.a=rsa-sha256 header.s=protonmail3 header.b=nc4YWVM/ +``` + ### Test SPF, DKIM, and DMARC You can use [mail-tester.com](https://www.mail-tester.com/) and send an email from your domain to check that SPF, DKIM, From 3b2361ef62f36b1bc3fa10fd58e4a72defbd0aa5 Mon Sep 17 00:00:00 2001 From: revsuine Date: Sun, 24 Nov 2024 00:50:18 +0000 Subject: [PATCH 4/8] content/blog/mail_server_alpine_postfix_dovecot_tutorial.md: pigeonhole section --- .../index.md | 140 ++++++++++++++++++ 1 file changed, 140 insertions(+) diff --git a/content/blog/mail_server_alpine_postfix_dovecot_tutorial/index.md b/content/blog/mail_server_alpine_postfix_dovecot_tutorial/index.md index 6a05ccb..aa48f4a 100644 --- a/content/blog/mail_server_alpine_postfix_dovecot_tutorial/index.md +++ b/content/blog/mail_server_alpine_postfix_dovecot_tutorial/index.md @@ -224,6 +224,7 @@ following TCP ports are open on your firewall: | 465 | Email message submission over TLS | | 587 | Email message submission | | 993 | IMAPS (IMAP over TLS) | +| 4190 | ManageSieve | ## Obtain a TLS certificate @@ -1307,6 +1308,11 @@ instance](#a-note-on-my-dns-records), this is `master.revsuine.xyz`). TrustedAuthservIDs mail.domain.com ``` +This specifies that OpenDMARC should trust authentication results from `mail.domain.com`. Otherwise you would get the +following error message in your syslog: + + ignoring Authentication-Results at 1 from mail.domain.com + Enable `RejectFailures`, which means your server will comply with `p=reject` in DMARC DNS records. ```conf @@ -1388,6 +1394,10 @@ Authentication-Results: master.revsuine.xyz; dkim=pass (2048-bit key; secure) header.d=protonmail.com header.i=@protonmail.com header.a=rsa-sha256 header.s=protonmail3 header.b=nc4YWVM/ ``` + + ### Test SPF, DKIM, and DMARC You can use [mail-tester.com](https://www.mail-tester.com/) and send an email from your domain to check that SPF, DKIM, @@ -1619,6 +1629,136 @@ X-Spam-Status: Yes, score=999.802 tagged_above=2 required=6.2 URIBL_ZEN_BLOCKED_OPENDNS=0.001] autolearn=no autolearn_force=no ``` +# Pigeonhole + +Dovecot can do server-side mail filtering with sieve scripts. These are user scripts that can perform actions on mail +based on particular criteria, e.g. + +```sieve +require "fileinto"; + +if address :is "to" "postmaster@revsuine.xyz" { + fileinto "Postmaster"; +} +``` + +Places mail in the `Postmaster` folder if the `To:` field is `postmaster@revsuine.xyz`. You also can do things +unconditionally, like + +```sieve +redirect postmaster@revsuine.xyz; +``` + +unconditionally redirects all mail to `postmaster@revsuine.xyz`. + +Sieve scripts can be both per-user and system-wide. + +For more examples, [this page](https://doc.dovecot.org/main/howto/sieve.html) has some good examples. + +## Installing and setting up Pigeonhole + +To use Sieve, install `dovecot-pigeonhole-plugin`: + + # apk add dovecot-pigeonhole-plugin + +Then edit `/etc/dovecot/conf.d/20-lmtp.conf`, and add the `sieve` plugin like so: + +```conf +protocol lmtp { + # Space separated list of plugins to load (default is global mail_plugins). + mail_plugins = $mail_plugins sieve +} +``` + +To configure Pigeonhole and sieve, edit `/etc/dovecot/conf.d/90-sieve.conf`. Sieve's options will be configured in the +`plugin {}` block in this file. + +We can set the location of user sieve scripts with the `sieve` option. + +```conf +sieve = file:~/sieve;active=~/.dovecot.sieve +``` + +means that `~/sieve` is a directory of sieve scripts, whilst `~/.dovecot.sieve` is a symlink to the "active" one, e.g. + +``` +sieve +├── script1.sieve +├── script2.sieve +└── script3.sieve +``` + +could be your `~/sieve/` directory, and to make `script2.sieve` active, you would do + + $ ln -s ~/sieve/script2.sieve ~/.dovecot.sieve + +`sieve_before` defines a directory of sieve scripts which will be executed *prior* to any user scripts. e.g. + +```conf +sieve_before = /etc/dovecot/sieve +``` + +means that the sieve scripts in `/etc/dovecot/sieve` will be executed first, then the user's personal scripts at +`~/.dovecot.sieve`. + +You can specify multiple directories in order, like so: + +```conf +sieve_before = /var/lib/dovecot/sieve.d/ +sieve_before2 = ldap:/etc/sieve-ldap.conf;name=ldap-domain +sieve_before3 = /etc/dovecot/sieve +``` + +etc. The `sieve_after` option also exists, and works the same way. + +This is not the same as `sieve_default`, which is *overridden* by user sieve scripts and only executes when a user has +no sieve script. + +## ManageSieve + +Users can configure their own user sieve scripts using a protocol called ManageSieve. Like how IMAP allows users to +read their emails without having shell access to the mail server, ManageSieve allows users to write sieve scripts +without requiring shell access. + +To enable ManageSieve, edit `/etc/dovecot/conf.d/20-managesieve.conf`. Make sure the following line is uncommented: + +```conf +protocols = $protocols sieve +``` + +By default, ManageSieve will listen on port 4190. + +## Sieve scripts for spam filtering + +Let's use a system-wide sieve script to file SpamAssassin-marked spam into a Spam folder. Create an +`/etc/dovecot/sieve/` directory, and add it to your `sieve_before` settings: + +```conf +plugin { + ... + sieve_before = /etc/dovecot/sieve/ + ... +} +``` + +Now create a new sieve script, `/etc/dovecot/sieve/spam_folder.sieve`: + +```sieve +require ["fileinto", "mailbox"]; +if header :contains "X-Spam-Flag" "YES" { + fileinto :create "Spam"; +} +``` + +Replace `"Spam"` with the name of your spam folder. If it's a subfolder, e.g. + +``` +Inbox +└── Spam +``` + +you would write `"Inbox.Spam"` in that case. + # Miscellaneous suggestions You may want to get your domain whitelisted on [dnswl.org](https://www.dnswl.org/), an email whitelist service where From 327327717b3de9c47462b9cc984494b9bfa1e1d1 Mon Sep 17 00:00:00 2001 From: revsuine Date: Sun, 24 Nov 2024 01:49:05 +0000 Subject: [PATCH 5/8] content/blog/mail_server_alpine_postfix_dovecot_tutorial: code blocks css improvements --- assets/css/prism.css | 69 ++++++++++++++++++++++++++++++++++++++++++- assets/css/syntax.css | 5 +++- 2 files changed, 72 insertions(+), 2 deletions(-) diff --git a/assets/css/prism.css b/assets/css/prism.css index b570451..4367b25 100644 --- a/assets/css/prism.css +++ b/assets/css/prism.css @@ -11,7 +11,7 @@ code[class*="language-"], pre[class*="language-"] { color: #ebdbb2; /* fg1 / fg */ - font-family: Consolas, Monaco, "Andale Mono", monospace; + font-family: "Fira Code", "Ubuntu Mono", Consolas, Monaco, "Andale Mono", monospace; direction: ltr; text-align: left; white-space: pre; @@ -141,3 +141,70 @@ pre[class*="language-"] { .token.deleted { background: #fb4934; /* red2 */ } + +/* css for hover button from https://github.com/panr/hugo-theme-terminal/blob/master/assets/css/prism.css */ + +div.code-toolbar { + position: relative; +} + +div.code-toolbar > .toolbar { + position: absolute; + top: 0.3em; + right: 0.2em; + transition: opacity 0.3s ease-in-out; + opacity: 0; +} + +div.code-toolbar:hover > .toolbar { + opacity: 1; +} + +/* Separate line b/c rules are thrown out if selector is invalid. + IE11 and old Edge versions don't support :focus-within. */ +div.code-toolbar:focus-within > .toolbar { + opacity: 1; +} + +div.code-toolbar > .toolbar > .toolbar-item { + display: inline-block; +} + +div.code-toolbar > .toolbar > .toolbar-item > a { + cursor: pointer; +} + +div.code-toolbar > .toolbar > .toolbar-item > button { + background: none; + border: 0; + color: inherit; + font: inherit; + line-height: normal; + overflow: visible; + padding: 0; + + /* for button */ + user-select: none; +} + +div.code-toolbar > .toolbar > .toolbar-item > a, +div.code-toolbar > .toolbar > .toolbar-item > button, +div.code-toolbar > .toolbar > .toolbar-item > span { + color: #bbb; + font-size: 0.8em; + padding: 0 0.5em; + background: #f5f2f0; + background: rgba(224, 224, 224, 20%); + box-shadow: 0 2px 0 0 rgba(0, 0, 0, 20%); + border-radius: 0.5em; +} + +div.code-toolbar > .toolbar > .toolbar-item > a:hover, +div.code-toolbar > .toolbar > .toolbar-item > a:focus, +div.code-toolbar > .toolbar > .toolbar-item > button:hover, +div.code-toolbar > .toolbar > .toolbar-item > button:focus, +div.code-toolbar > .toolbar > .toolbar-item > span:hover, +div.code-toolbar > .toolbar > .toolbar-item > span:focus { + color: inherit; + text-decoration: none; +} diff --git a/assets/css/syntax.css b/assets/css/syntax.css index 2349aa2..f10338f 100644 --- a/assets/css/syntax.css +++ b/assets/css/syntax.css @@ -1,2 +1,5 @@ -/* overriding syntax.css */ +pre[class*=language-] { + margin: 0; + overflow: auto; +} From 6d51d4f4f8a3a4a21b1b1fe7b1992024b0ab1f85 Mon Sep 17 00:00:00 2001 From: revsuine Date: Sun, 24 Nov 2024 02:45:17 +0000 Subject: [PATCH 6/8] content/blog/mail_server_alpine_postfix_dovecot_tutorial.md: mail_crypt section --- .../index.md | 63 ++++++++++++++++++- 1 file changed, 60 insertions(+), 3 deletions(-) diff --git a/content/blog/mail_server_alpine_postfix_dovecot_tutorial/index.md b/content/blog/mail_server_alpine_postfix_dovecot_tutorial/index.md index aa48f4a..8aa1b5a 100644 --- a/content/blog/mail_server_alpine_postfix_dovecot_tutorial/index.md +++ b/content/blog/mail_server_alpine_postfix_dovecot_tutorial/index.md @@ -28,8 +28,8 @@ ports](#unblock-your-ports). I'll cut to the chase: the main reason why you'd want to run your own mail server is for related reasons of privacy and digital sovereignty. For privacy benefits, as much as you have control over your server, you can protect your email -from the eyes of prying server admins (given that you yourself are the admin). Even for email providers that market -themselves around privacy such as Protonmail, rely on trust that Proton are not reading your unencrypted incoming +from the eyes of prying server admins (given that you yourself are the admin). Even email providers that market +themselves around privacy (e.g. Protonmail) rely on trust that the provider is not reading your unencrypted incoming email. This is not an issue exclusive to any particular mail provider; if information arrives unencrypted at a server, those with access to the server (i.e. administrators) can read that information, simple as. And as nice as it would be if everyone used GPG end-to-end encryption for email, the vast majority of emails people receive are not end-to-end @@ -741,6 +741,63 @@ get an error message when restarting. # rc-update add dovecot default # rc-service dovecot start +## mail\_crypt + +Dovecot has a [mail\_crypt plugin](https://doc.dovecot.org/main/core/plugins/mail_crypt.html) which implements +**transparent** encryption at rest for mail. By transparent, I mean "invisible" to email clients; you can use an IMAP +client with your server with no changes, and no difference in user experience. Mail is decrypted on the server and sent +over IMAP. + +We will optionally set up global key mail\_crypt encryption. This does not provider protection against an attacker with +root access, or full disk access (which is basically root access), however it can protect against other processes +reading our mail since they can't read the private key. + +If you want to implement it, declare usage of the `mail_crypt` plugin in `/etc/dovecot/dovecot.conf`: + +```conf +mail_plugins = $mail_plugins mail_crypt +``` + +Now let's generate some elliptic curve keys for this. + +See what curves are available: + + $ openssl ecparam -list_curves + +If we pick `prime256v1` as our curve, then run: + + $ openssl ecparam -name prime256v1 -genkey | openssl pkey -out ecprivkey.pem + +to generate the private key. To generate the public key: + + $ openssl pkey -in ecprivkey.pem -pubout -out ecpubkey.pem + +Now move these keys to `/etc/dovecot/` and make sure they are owned by `dovecot`: + + # mv ecpubkey.pem /etc/dovecot + # mv ecprivkey.pem /etc/dovecot + # chown dovecot:dovecot ecpubkey.pem ecprivkey.pem + +Give them the correct permissions: + + $ cd /etc/dovecot + # chmod 644 ecpubkey.pem + # chmod 600 ecprivkey.pem + +Anyway, create and edit `/etc/dovecot/conf.d/90-mail_crypt.conf` and configure the plugin as follows: + +```conf +plugin { + mail_crypt_global_private_key = Received: from master.revsuine.xyz (master.revsuine.xyz. [93.113.25.226]) by mx.google.com with ESMTPS id ffacd0b85a97d-3825fb5a132si1538595f8f.66.2024.11.22.08.53.01 From 8cf0f5313fc7a9fdc6f9bda012405b99d8ce91f1 Mon Sep 17 00:00:00 2001 From: revsuine Date: Sun, 24 Nov 2024 02:55:27 +0000 Subject: [PATCH 7/8] content/blog/mail_server_alpine_postfix_dovecot_tutorial.md: mail_crypt typo + extra sentence --- .../blog/mail_server_alpine_postfix_dovecot_tutorial/index.md | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/content/blog/mail_server_alpine_postfix_dovecot_tutorial/index.md b/content/blog/mail_server_alpine_postfix_dovecot_tutorial/index.md index 8aa1b5a..b22ad3d 100644 --- a/content/blog/mail_server_alpine_postfix_dovecot_tutorial/index.md +++ b/content/blog/mail_server_alpine_postfix_dovecot_tutorial/index.md @@ -748,7 +748,7 @@ Dovecot has a [mail\_crypt plugin](https://doc.dovecot.org/main/core/plugins/mai client with your server with no changes, and no difference in user experience. Mail is decrypted on the server and sent over IMAP. -We will optionally set up global key mail\_crypt encryption. This does not provider protection against an attacker with +We will optionally set up global key mail\_crypt encryption. This does not provide protection against an attacker with root access, or full disk access (which is basically root access), however it can protect against other processes reading our mail since they can't read the private key. @@ -798,6 +798,8 @@ Restart Dovecot for the changes to take effect: # rc-service dovecot restart +Note that this will not make any difference to reading unencrypted email that was previously stored in your mailbox. + # Use a local email client You are now ready to try logging in on a local email client such as Thunderbird, Evolution, Geary, KMail, etc. From 754a1eb803ce0b20239ccab083a98fadb6b10836 Mon Sep 17 00:00:00 2001 From: revsuine Date: Sun, 24 Nov 2024 02:56:54 +0000 Subject: [PATCH 8/8] content/blog/mail_server_alpine_postfix_dovecot_tutorial.md: pigeonhole link to documentation --- .../blog/mail_server_alpine_postfix_dovecot_tutorial/index.md | 3 +++ 1 file changed, 3 insertions(+) diff --git a/content/blog/mail_server_alpine_postfix_dovecot_tutorial/index.md b/content/blog/mail_server_alpine_postfix_dovecot_tutorial/index.md index b22ad3d..5c4e719 100644 --- a/content/blog/mail_server_alpine_postfix_dovecot_tutorial/index.md +++ b/content/blog/mail_server_alpine_postfix_dovecot_tutorial/index.md @@ -1773,6 +1773,9 @@ etc. The `sieve_after` option also exists, and works the same way. This is not the same as `sieve_default`, which is *overridden* by user sieve scripts and only executes when a user has no sieve script. +You can review [this documentation](https://doc.dovecot.org/main/core/plugins/sieve.html) for a full list of Pigeonhole +options. + ## ManageSieve Users can configure their own user sieve scripts using a protocol called ManageSieve. Like how IMAP allows users to