diff --git a/hosts/by-name/servo/services/email/dovecot.nix b/hosts/by-name/servo/services/email/dovecot.nix
index 7c59f75f..9c8f1c5b 100644
--- a/hosts/by-name/servo/services/email/dovecot.nix
+++ b/hosts/by-name/servo/services/email/dovecot.nix
@@ -1,5 +1,10 @@
# dovecot config options:
-{ config, ... }:
+#
+# sieve docs:
+# - sieve language examples:
+# - sieve protocol/language:
+
+{ config, lib, pkgs, ... }:
{
networking.firewall.allowedTCPPorts = [
# exposed over non-vpn imap.uninsane.org
@@ -24,31 +29,16 @@
# inspired by https://gitlab.com/simple-nixos-mailserver/nixos-mailserver/
services.dovecot2.enable = true;
- services.dovecot2.mailboxes = {
- # special-purpose mailboxes: "All" "Archive" "Drafts" "Flagged" "Junk" "Sent" "Trash"
- # RFC6154 describes these special mailboxes: https://www.ietf.org/rfc/rfc6154.html
- # how these boxes are treated is 100% up to the client and server to decide.
- # client behavior:
- # iOS
- # - Drafts: ?
- # - Sent: works
- # - Trash: works
- # - Junk: ?
- # aerc
- # - Drafts: works
- # - Sent: works
- # - Trash: no; deleted messages are actually deleted
- # use `:move trash` instead
- # - Junk: ?
- # Sent mailbox: all sent messages are copied to it. unclear if this happens server-side or client-side.
- Drafts = { specialUse = "Drafts"; auto = "create"; };
- Sent = { specialUse = "Sent"; auto = "create"; };
- Trash = { specialUse = "Trash"; auto = "create"; };
- Junk = { specialUse = "Junk"; auto = "create"; };
- };
+ # services.dovecot2.enableLmtp = true;
services.dovecot2.sslServerCert = "/var/lib/acme/imap.uninsane.org/fullchain.pem";
services.dovecot2.sslServerKey = "/var/lib/acme/imap.uninsane.org/key.pem";
services.dovecot2.enablePAM = false;
+
+ # sieve scripts require me to set a user for... idk why?
+ services.dovecot2.mailUser = "colin";
+ services.dovecot2.mailGroup = "users";
+ users.users.colin.isSystemUser = lib.mkForce false;
+
services.dovecot2.extraConfig =
let
passwdFile = config.sops.secrets.dovecot_passwd.path;
@@ -73,9 +63,73 @@
}
auth_mechanisms = plain login
+ # accept incoming messaging from postfix
+ # service lmtp {
+ # unix_listener dovecot-lmtp {
+ # mode = 0600
+ # user = postfix
+ # group = postfix
+ # }
+ # }
+
+ # plugin {
+ # sieve_plugins = sieve_imapsieve
+ # }
mail_debug = yes
auth_debug = yes
# verbose_ssl = yes
'';
+
+ services.dovecot2.mailboxes = {
+ # special-purpose mailboxes: "All" "Archive" "Drafts" "Flagged" "Junk" "Sent" "Trash"
+ # RFC6154 describes these special mailboxes: https://www.ietf.org/rfc/rfc6154.html
+ # how these boxes are treated is 100% up to the client and server to decide.
+ # client behavior:
+ # iOS
+ # - Drafts: ?
+ # - Sent: works
+ # - Trash: works
+ # - Junk: works ("mark" -> "move to Junk")
+ # aerc
+ # - Drafts: works
+ # - Sent: works
+ # - Trash: no; deleted messages are actually deleted
+ # use `:move trash` instead
+ # - Junk: ?
+ # Sent mailbox: all sent messages are copied to it. unclear if this happens server-side or client-side.
+ Drafts = { specialUse = "Drafts"; auto = "create"; };
+ Sent = { specialUse = "Sent"; auto = "create"; };
+ Trash = { specialUse = "Trash"; auto = "create"; };
+ Junk = { specialUse = "Junk"; auto = "create"; };
+ };
+
+ services.dovecot2.mailPlugins = {
+ perProtocol = {
+ # imap.enable = [
+ # "imap_sieve"
+ # ];
+ lda.enable = [
+ "sieve"
+ ];
+ # lmtp.enable = [
+ # "sieve"
+ # ];
+ };
+ };
+ services.dovecot2.modules = [
+ pkgs.dovecot_pigeonhole # enables sieve execution (?)
+ ];
+ services.dovecot2.sieveScripts = {
+ # if any messages fail to pass (or lack) DKIM, move them to Junk
+ # XXX the key name ("after") is only used to order sieve execution/ordering
+ after = builtins.toFile "ensuredkim.sieve" ''
+ require "fileinto";
+
+ if not header :contains "Authentication-Results" "dkim=pass" {
+ fileinto "Junk";
+ stop;
+ }
+ '';
+ };
}
diff --git a/hosts/by-name/servo/services/email/postfix.nix b/hosts/by-name/servo/services/email/postfix.nix
index 946a6f30..b6539547 100644
--- a/hosts/by-name/servo/services/email/postfix.nix
+++ b/hosts/by-name/servo/services/email/postfix.nix
@@ -1,6 +1,6 @@
# postfix config options:
-{ lib, ... }:
+{ lib, pkgs, ... }:
let
submissionOptions = {
@@ -88,24 +88,40 @@ in
@uninsane.org colin
'';
- services.postfix.extraConfig = ''
+ services.postfix.config = {
# smtpd_milters = local:/run/opendkim/opendkim.sock
# milter docs: http://www.postfix.org/MILTER_README.html
- # mail filters for receiving email and authorized SMTP clients
+ # mail filters for receiving email and from authorized SMTP clients (i.e. via submission)
# smtpd_milters = inet:185.157.162.190:8891
- smtpd_milters = unix:/run/opendkim/opendkim.sock
+ # opendkim.sock will add a Authentication-Results header, with `dkim=pass|fail|...` value to received messages
+ smtpd_milters = "unix:/run/opendkim/opendkim.sock";
# mail filters for sendmail
- non_smtpd_milters = $smtpd_milters
- milter_default_action = accept
- inet_protocols = ipv4
- smtp_tls_security_level = may
+ non_smtpd_milters = "$smtpd_milters";
+
+ # what to do when a milter exits unexpectedly:
+ milter_default_action = "accept";
+
+ inet_protocols = "ipv4";
+ smtp_tls_security_level = "may";
+
+ # hand received mail over to dovecot so that it can run sieves & such
+ mailbox_command = ''${pkgs.dovecot}/libexec/dovecot/dovecot-lda -f "$SENDER" -a "$RECIPIENT"'';
+
+ # hand received mail over to dovecot
+ # virtual_alias_maps = [
+ # "hash:/etc/postfix/virtual"
+ # ];
+ # mydestination = "";
+ # virtual_mailbox_domains = [ "localhost" "uninsane.org" ];
+ # # virtual_mailbox_maps = "hash:/etc/postfix/virtual";
+ # virtual_transport = "lmtp:unix:/run/dovecot2/dovecot-lmtp";
# anti-spam options:
# reject_unknown_sender_domain: causes postfix to `dig MX` and make sure that exists.
# but may cause problems receiving mail from google & others who load-balance?
# -
# smtpd_sender_restrictions = reject_unknown_sender_domain
- '';
+ };
services.postfix.enableSubmission = true;
services.postfix.submissionOptions = submissionOptions;
@@ -120,6 +136,8 @@ in
};
+ #### OPENDKIM
+
services.opendkim.enable = true;
# services.opendkim.domains = "csl:uninsane.org";
services.opendkim.domains = "uninsane.org";