2024-02-07 01:22:34 +00:00
{ config , lib , pkgs , . . . }:
2020-04-24 23:36:52 +00:00
let
2024-02-07 01:22:34 +00:00
inherit ( lib ) attrValues concatMapStringsSep concatStrings
concatStringsSep flatten imap1 literalExpression mapAttrsToList
2024-01-13 08:15:51 +00:00
mkEnableOption mkIf mkOption mkRemovedOptionModule optional optionalAttrs
2024-02-07 01:22:34 +00:00
optionalString singleton types mkRenamedOptionModule nameValuePair
mapAttrs' listToAttrs filter ;
inherit ( lib . strings ) match ;
2024-01-13 08:15:51 +00:00
2020-04-24 23:36:52 +00:00
cfg = config . services . dovecot2 ;
dovecotPkg = pkgs . dovecot ;
baseDir = " / r u n / d o v e c o t 2 " ;
stateDir = " / v a r / l i b / d o v e c o t " ;
2024-02-07 01:22:34 +00:00
sieveScriptSettings = mapAttrs' ( to : _ : nameValuePair " s i e v e _ ${ to } " " ${ stateDir } / s i e v e / ${ to } " ) cfg . sieve . scripts ;
imapSieveMailboxSettings = listToAttrs ( flatten ( imap1 ( idx : el :
singleton {
name = " i m a p s i e v e _ m a i l b o x ${ toString idx } _ n a m e " ;
value = el . name ;
} ++ optional ( el . from != null ) {
name = " i m a p s i e v e _ m a i l b o x ${ toString idx } _ f r o m " ;
value = el . from ;
} ++ optional ( el . causes != [ ] ) {
name = " i m a p s i e v e _ m a i l b o x ${ toString idx } _ c a u s e s " ;
value = concatStringsSep " , " el . causes ;
} ++ optional ( el . before != null ) {
name = " i m a p s i e v e _ m a i l b o x ${ toString idx } _ b e f o r e " ;
value = " f i l e : ${ stateDir } / i m a p s i e v e / b e f o r e / ${ baseNameOf el . before } " ;
} ++ optional ( el . after != null ) {
name = " i m a p s i e v e _ m a i l b o x ${ toString idx } _ a f t e r " ;
value = " f i l e : ${ stateDir } / i m a p s i e v e / a f t e r / ${ baseNameOf el . after } " ;
}
) cfg . imapsieve . mailbox ) ) ;
mkExtraConfigCollisionWarning = term : ''
You referred to $ { term } in ` services . dovecot2 . extraConfig ` .
Due to gradual transition to structured configuration for plugin configuration , it is possible
this will cause your plugin configuration to be ignored .
Consider setting ` services . dovecot2 . pluginSettings . ${ term } ` instead .
'' ;
# Those settings are automatically set based on other parts
# of this module.
automaticallySetPluginSettings = [
" s i e v e _ p l u g i n s "
" s i e v e _ e x t e n s i o n s "
" s i e v e _ g l o b a l _ e x t e n s i o n s "
" s i e v e _ p i p e _ b i n _ d i r "
]
++ ( builtins . attrNames sieveScriptSettings )
++ ( builtins . attrNames imapSieveMailboxSettings ) ;
# The idea is to match everything that looks like `$term =`
# but not `# $term something something`
# or `# $term = some value` because those are comments.
configContainsSetting = lines : term : ( match " ^ [ ^ # ] * \b ${ term } \b . * = " lines ) != null ;
warnAboutExtraConfigCollisions = map mkExtraConfigCollisionWarning ( filter ( configContainsSetting cfg . extraConfig ) automaticallySetPluginSettings ) ;
sievePipeBinScriptDirectory = pkgs . linkFarm " s i e v e - p i p e - b i n s " ( map ( el : {
name = builtins . unsafeDiscardStringContext ( baseNameOf el ) ;
path = el ;
} ) cfg . sieve . pipeBins ) ;
2020-04-24 23:36:52 +00:00
dovecotConf = concatStrings [
''
base_dir = $ { baseDir }
protocols = $ { concatStringsSep " " cfg . protocols }
sendmail_path = /run/wrappers/bin/sendmail
# defining mail_plugins must be done before the first protocol {} filter because of https://doc.dovecot.org/configuration_manual/config_file/config_file_syntax/#variable-expansion
mail_plugins = $ mail_plugins $ { concatStringsSep " " cfg . mailPlugins . globally . enable }
''
(
concatStringsSep " \n " (
mapAttrsToList (
protocol : plugins : ''
protocol $ { protocol } {
mail_plugins = $ mail_plugins $ { concatStringsSep " " plugins . enable }
}
''
) cfg . mailPlugins . perProtocol
)
)
(
if cfg . sslServerCert == null then ''
ssl = no
disable_plaintext_auth = no
'' e l s e ''
ssl_cert = < $ { cfg . sslServerCert }
ssl_key = < $ { cfg . sslServerKey }
$ { optionalString ( cfg . sslCACert != null ) ( " s s l _ c a = < " + cfg . sslCACert ) }
2022-01-23 02:10:13 +00:00
$ { optionalString cfg . enableDHE '' s s l _ d h = < ${ config . security . dhparams . params . dovecot2 . path } '' }
2020-04-24 23:36:52 +00:00
disable_plaintext_auth = yes
''
)
''
default_internal_user = $ { cfg . user }
default_internal_group = $ { cfg . group }
$ { optionalString ( cfg . mailUser != null ) " m a i l _ u i d = ${ cfg . mailUser } " }
$ { optionalString ( cfg . mailGroup != null ) " m a i l _ g i d = ${ cfg . mailGroup } " }
mail_location = $ { cfg . mailLocation }
maildir_copy_with_hardlinks = yes
pop3_uidl_format = % 0 8 Xv % 0 8 Xu
auth_mechanisms = plain login
service auth {
user = root
}
''
(
optionalString cfg . enablePAM ''
userdb {
driver = passwd
}
passdb {
driver = pam
args = $ { optionalString cfg . showPAMFailure " f a i l u r e _ s h o w _ m s g = y e s " } dovecot2
}
''
)
(
2020-09-25 04:45:31 +00:00
optionalString ( cfg . mailboxes != { } ) ''
2020-10-07 09:15:18 +00:00
namespace inbox {
inbox = yes
$ { concatStringsSep " \n " ( map mailboxConfig ( attrValues cfg . mailboxes ) ) }
2020-04-24 23:36:52 +00:00
}
''
)
(
optionalString cfg . enableQuota ''
service quota-status {
executable = $ { dovecotPkg } /libexec/dovecot/quota-status - p postfix
inet_listener {
port = $ { cfg . quotaPort }
}
client_limit = 1
}
plugin {
quota_rule = * : storage = $ { cfg . quotaGlobalPerUser }
2021-12-06 16:07:01 +00:00
quota = count:User quota # per virtual mail user quota
2020-04-24 23:36:52 +00:00
quota_status_success = DUNNO
quota_status_nouser = DUNNO
quota_status_overquota = " 5 5 2 5 . 2 . 2 M a i l b o x i s f u l l "
quota_grace = 10 % %
2021-12-06 16:07:01 +00:00
quota_vsizes = yes
2020-04-24 23:36:52 +00:00
}
''
)
2024-02-07 01:22:34 +00:00
# General plugin settings:
# - sieve is mostly generated here, refer to `pluginSettings` to follow
# the control flow.
2024-01-13 08:15:51 +00:00
''
plugin {
2024-02-07 01:22:34 +00:00
$ { concatStringsSep " \n " ( mapAttrsToList ( key : value : " ${ key } = ${ value } " ) cfg . pluginSettings ) }
2024-01-13 08:15:51 +00:00
}
''
2020-04-24 23:36:52 +00:00
cfg . extraConfig
] ;
modulesDir = pkgs . symlinkJoin {
name = " d o v e c o t - m o d u l e s " ;
paths = map ( pkg : " ${ pkg } / l i b / d o v e c o t " ) ( [ dovecotPkg ] ++ map ( module : module . override { dovecot = dovecotPkg ; } ) cfg . modules ) ;
} ;
mailboxConfig = mailbox : ''
mailbox " ${ mailbox . name } " {
auto = $ { toString mailbox . auto }
2020-06-18 07:06:33 +00:00
'' + o p t i o n a l S t r i n g ( m a i l b o x . a u t o e x p u n g e ! = n u l l ) ''
autoexpunge = $ { mailbox . autoexpunge }
2020-04-24 23:36:52 +00:00
'' + o p t i o n a l S t r i n g ( m a i l b o x . s p e c i a l U s e ! = n u l l ) ''
special_use = \ $ { toString mailbox . specialUse }
'' + " } " ;
2020-09-25 04:45:31 +00:00
mailboxes = { name , . . . }: {
2020-04-24 23:36:52 +00:00
options = {
name = mkOption {
2020-09-25 04:45:31 +00:00
type = types . strMatching '' [ ^ " ] + '' ;
2020-04-24 23:36:52 +00:00
example = " S p a m " ;
2020-09-25 04:45:31 +00:00
default = name ;
readOnly = true ;
2022-08-12 12:06:08 +00:00
description = lib . mdDoc " T h e n a m e o f t h e m a i l b o x . " ;
2020-04-24 23:36:52 +00:00
} ;
auto = mkOption {
type = types . enum [ " n o " " c r e a t e " " s u b s c r i b e " ] ;
default = " n o " ;
example = " s u b s c r i b e " ;
2022-08-12 12:06:08 +00:00
description = lib . mdDoc " W h e t h e r t o a u t o m a t i c a l l y c r e a t e o r c r e a t e a n d s u b s c r i b e t o t h e m a i l b o x o r n o t . " ;
2020-04-24 23:36:52 +00:00
} ;
specialUse = mkOption {
type = types . nullOr ( types . enum [ " A l l " " A r c h i v e " " D r a f t s " " F l a g g e d " " J u n k " " S e n t " " T r a s h " ] ) ;
default = null ;
example = " J u n k " ;
2022-08-12 12:06:08 +00:00
description = lib . mdDoc " N u l l i f n o s p e c i a l u s e f l a g i s s e t . O t h e r t h a n t h a t e v e r y u s e f l a g m e n t i o n e d i n t h e R F C i s v a l i d . " ;
2020-04-24 23:36:52 +00:00
} ;
2020-06-18 07:06:33 +00:00
autoexpunge = mkOption {
type = types . nullOr types . str ;
default = null ;
example = " 6 0 d " ;
2022-08-12 12:06:08 +00:00
description = lib . mdDoc ''
2020-06-18 07:06:33 +00:00
To automatically remove all email from the mailbox which is older than the
specified time .
'' ;
} ;
2020-04-24 23:36:52 +00:00
} ;
} ;
in
{
imports = [
( mkRemovedOptionModule [ " s e r v i c e s " " d o v e c o t 2 " " p a c k a g e " ] " " )
2024-02-07 01:22:34 +00:00
( mkRenamedOptionModule [ " s e r v i c e s " " d o v e c o t 2 " " s i e v e S c r i p t s " ] [ " s e r v i c e s " " d o v e c o t 2 " " s i e v e " " s c r i p t s " ] )
2020-04-24 23:36:52 +00:00
] ;
options . services . dovecot2 = {
2022-09-09 14:08:57 +00:00
enable = mkEnableOption ( lib . mdDoc " t h e d o v e c o t 2 . x P O P 3 / I M A P s e r v e r " ) ;
2020-04-24 23:36:52 +00:00
2023-02-09 11:40:11 +00:00
enablePop3 = mkEnableOption ( lib . mdDoc " s t a r t i n g t h e P O P 3 l i s t e n e r ( w h e n D o v e c o t i s e n a b l e d ) " ) ;
2020-04-24 23:36:52 +00:00
2023-02-09 11:40:11 +00:00
enableImap = mkEnableOption ( lib . mdDoc " s t a r t i n g t h e I M A P l i s t e n e r ( w h e n D o v e c o t i s e n a b l e d ) " ) // { default = true ; } ;
2020-04-24 23:36:52 +00:00
2023-02-09 11:40:11 +00:00
enableLmtp = mkEnableOption ( lib . mdDoc " s t a r t i n g t h e L M T P l i s t e n e r ( w h e n D o v e c o t i s e n a b l e d ) " ) ;
2020-04-24 23:36:52 +00:00
protocols = mkOption {
type = types . listOf types . str ;
default = [ ] ;
2022-08-12 12:06:08 +00:00
description = lib . mdDoc " A d d i t i o n a l l i s t e n e r s t o s t a r t w h e n D o v e c o t i s e n a b l e d . " ;
2020-04-24 23:36:52 +00:00
} ;
user = mkOption {
type = types . str ;
default = " d o v e c o t 2 " ;
2022-08-12 12:06:08 +00:00
description = lib . mdDoc " D o v e c o t u s e r n a m e . " ;
2020-04-24 23:36:52 +00:00
} ;
group = mkOption {
type = types . str ;
default = " d o v e c o t 2 " ;
2022-08-12 12:06:08 +00:00
description = lib . mdDoc " D o v e c o t g r o u p n a m e . " ;
2020-04-24 23:36:52 +00:00
} ;
extraConfig = mkOption {
type = types . lines ;
default = " " ;
example = " m a i l _ d e b u g = y e s " ;
2022-08-12 12:06:08 +00:00
description = lib . mdDoc " A d d i t i o n a l e n t r i e s t o p u t v e r b a t i m i n t o D o v e c o t ' s c o n f i g f i l e . " ;
2020-04-24 23:36:52 +00:00
} ;
mailPlugins =
let
plugins = hint : types . submodule {
options = {
enable = mkOption {
type = types . listOf types . str ;
default = [ ] ;
2022-08-12 12:06:08 +00:00
description = lib . mdDoc " m a i l p l u g i n s t o e n a b l e a s a l i s t o f s t r i n g s t o a p p e n d t o t h e ${ hint } ` $ m a i l _ p l u g i n s ` c o n f i g u r a t i o n v a r i a b l e " ;
2020-04-24 23:36:52 +00:00
} ;
} ;
} ;
in
mkOption {
type = with types ; submodule {
options = {
globally = mkOption {
2022-08-12 12:06:08 +00:00
description = lib . mdDoc " A d d i t i o n a l e n t r i e s t o a d d t o t h e m a i l _ p l u g i n s v a r i a b l e f o r a l l p r o t o c o l s " ;
2020-04-24 23:36:52 +00:00
type = plugins " t o p - l e v e l " ;
example = { enable = [ " v i r t u a l " ] ; } ;
default = { enable = [ ] ; } ;
} ;
perProtocol = mkOption {
2022-08-12 12:06:08 +00:00
description = lib . mdDoc " A d d i t i o n a l e n t r i e s t o a d d t o t h e m a i l _ p l u g i n s v a r i a b l e , p e r p r o t o c o l " ;
2020-04-24 23:36:52 +00:00
type = attrsOf ( plugins " c o r r e s p o n d i n g p e r - p r o t o c o l " ) ;
default = { } ;
example = { imap = [ " i m a p _ a c l " ] ; } ;
} ;
} ;
} ;
2022-08-12 12:06:08 +00:00
description = lib . mdDoc " A d d i t i o n a l e n t r i e s t o a d d t o t h e m a i l _ p l u g i n s v a r i a b l e , g l o b a l l y a n d p e r p r o t o c o l " ;
2020-04-24 23:36:52 +00:00
example = {
globally . enable = [ " a c l " ] ;
perProtocol . imap . enable = [ " i m a p _ a c l " ] ;
} ;
default = { globally . enable = [ ] ; perProtocol = { } ; } ;
} ;
configFile = mkOption {
type = types . nullOr types . path ;
default = null ;
2022-08-12 12:06:08 +00:00
description = lib . mdDoc " C o n f i g f i l e u s e d f o r t h e w h o l e d o v e c o t c o n f i g u r a t i o n . " ;
2020-04-24 23:36:52 +00:00
apply = v : if v != null then v else pkgs . writeText " d o v e c o t . c o n f " dovecotConf ;
} ;
mailLocation = mkOption {
type = types . str ;
default = " m a i l d i r : / v a r / s p o o l / m a i l / % u " ; /* S a m e a s i n b o x , a s p o s t f i x */
example = " m a i l d i r : ~ / m a i l : I N B O X = / v a r / s p o o l / m a i l / % u " ;
2022-08-12 12:06:08 +00:00
description = lib . mdDoc ''
2020-04-24 23:36:52 +00:00
Location that dovecot will use for mail folders . Dovecot mail_location option .
'' ;
} ;
mailUser = mkOption {
type = types . nullOr types . str ;
default = null ;
2022-08-12 12:06:08 +00:00
description = lib . mdDoc " D e f a u l t u s e r t o s t o r e m a i l f o r v i r t u a l u s e r s . " ;
2020-04-24 23:36:52 +00:00
} ;
mailGroup = mkOption {
type = types . nullOr types . str ;
default = null ;
2022-08-12 12:06:08 +00:00
description = lib . mdDoc " D e f a u l t g r o u p t o s t o r e m a i l f o r v i r t u a l u s e r s . " ;
2020-04-24 23:36:52 +00:00
} ;
2022-09-09 14:08:57 +00:00
createMailUser = mkEnableOption ( lib . mdDoc '' a u t o m a t i c a l l y c r e a t i n g t h e u s e r
given in { option } ` services . dovecot . user ` and the group
given in { option } ` services . dovecot . group ` . '' ) / / { d e f a u l t = t r u e ; } ;
2020-04-24 23:36:52 +00:00
modules = mkOption {
type = types . listOf types . package ;
default = [ ] ;
2021-10-06 13:57:05 +00:00
example = literalExpression " [ p k g s . d o v e c o t _ p i g e o n h o l e ] " ;
2022-08-12 12:06:08 +00:00
description = lib . mdDoc ''
2020-04-24 23:36:52 +00:00
Symlinks the contents of lib/dovecot of every given package into
/etc/dovecot/modules. This will make the given modules available
if a dovecot package with the module_dir patch applied is being used .
'' ;
} ;
sslCACert = mkOption {
type = types . nullOr types . str ;
default = null ;
2022-08-12 12:06:08 +00:00
description = lib . mdDoc " P a t h t o t h e s e r v e r ' s C A c e r t i f i c a t e k e y . " ;
2020-04-24 23:36:52 +00:00
} ;
sslServerCert = mkOption {
type = types . nullOr types . str ;
default = null ;
2022-08-12 12:06:08 +00:00
description = lib . mdDoc " P a t h t o t h e s e r v e r ' s p u b l i c k e y . " ;
2020-04-24 23:36:52 +00:00
} ;
sslServerKey = mkOption {
type = types . nullOr types . str ;
default = null ;
2022-08-12 12:06:08 +00:00
description = lib . mdDoc " P a t h t o t h e s e r v e r ' s p r i v a t e k e y . " ;
2020-04-24 23:36:52 +00:00
} ;
2023-02-09 11:40:11 +00:00
enablePAM = mkEnableOption ( lib . mdDoc " c r e a t i n g a o w n D o v e c o t P A M s e r v i c e a n d c o n f i g u r e P A M u s e r l o g i n s " ) // { default = true ; } ;
2022-01-23 02:10:13 +00:00
2023-11-16 04:20:00 +00:00
enableDHE = mkEnableOption ( lib . mdDoc " s s l _ d h a n d g e n e r a t i o n o f p r i m e s f o r t h e k e y e x c h a n g e " ) // { default = true ; } ;
2020-04-24 23:36:52 +00:00
2023-02-09 11:40:11 +00:00
showPAMFailure = mkEnableOption ( lib . mdDoc " s h o w i n g t h e P A M f a i l u r e m e s s a g e o n a u t h e n t i c a t i o n e r r o r ( u s e f u l f o r O T P W ) " ) ;
2020-04-24 23:36:52 +00:00
mailboxes = mkOption {
2020-09-25 04:45:31 +00:00
type = with types ; coercedTo
( listOf unspecified )
( list : listToAttrs ( map ( entry : { name = entry . name ; value = removeAttrs entry [ " n a m e " ] ; } ) list ) )
( attrsOf ( submodule mailboxes ) ) ;
2020-06-18 07:06:33 +00:00
default = { } ;
2021-10-06 13:57:05 +00:00
example = literalExpression ''
2020-06-18 07:06:33 +00:00
{
Spam = { specialUse = " J u n k " ; auto = " c r e a t e " ; } ;
}
'' ;
2022-08-12 12:06:08 +00:00
description = lib . mdDoc " C o n f i g u r e m a i l b o x e s a n d a u t o c r e a t e o r s u b s c r i b e t h e m . " ;
2020-04-24 23:36:52 +00:00
} ;
2023-02-09 11:40:11 +00:00
enableQuota = mkEnableOption ( lib . mdDoc " t h e d o v e c o t q u o t a s e r v i c e " ) ;
2020-04-24 23:36:52 +00:00
quotaPort = mkOption {
type = types . str ;
default = " 1 2 3 4 0 " ;
2022-08-12 12:06:08 +00:00
description = lib . mdDoc ''
2020-04-24 23:36:52 +00:00
The Port the dovecot quota service binds to .
If using postfix , add check_policy_service inet:localhost:12340 to your smtpd_recipient_restrictions in your postfix config .
'' ;
} ;
quotaGlobalPerUser = mkOption {
type = types . str ;
default = " 1 0 0 G " ;
example = " 1 0 G " ;
2022-08-12 12:06:08 +00:00
description = lib . mdDoc " Q u o t a l i m i t f o r t h e u s e r i n b y t e s . S u p p o r t s s u f f i x e s b , k , M , G , T a n d % . " ;
2020-04-24 23:36:52 +00:00
} ;
2024-02-07 01:22:34 +00:00
pluginSettings = mkOption {
# types.str does not coerce from packages, like `sievePipeBinScriptDirectory`.
type = types . attrsOf ( types . oneOf [ types . str types . package ] ) ;
default = { } ;
example = literalExpression ''
{
sieve = " f i l e : ~ / s i e v e ; a c t i v e = ~ / . d o v e c o t . s i e v e " ;
}
'' ;
description = ''
Plugin settings for dovecot in general , e . g . ` sieve ` , ` sieve_default ` , etc .
Some of the other knobs of this module will influence by default the plugin settings , but you
can still override any plugin settings .
If you override a plugin setting , its value is cleared and you have to copy over the defaults .
'' ;
} ;
2024-01-13 08:15:51 +00:00
imapsieve . mailbox = mkOption {
default = [ ] ;
description = " C o n f i g u r e S i e v e f i l t e r i n g r u l e s o n I M A P a c t i o n s " ;
type = types . listOf ( types . submodule ( { config , . . . }: {
options = {
name = mkOption {
description = ''
This setting configures the name of a mailbox for which administrator scripts are configured .
The settings defined hereafter with matching sequence numbers apply to the mailbox named by this setting .
This setting supports wildcards with a syntax compatible with the IMAP LIST command , meaning that this setting can apply to multiple or even all ( " * " ) mailboxes .
'' ;
example = " J u n k " ;
type = types . str ;
} ;
from = mkOption {
default = null ;
description = ''
Only execute the administrator Sieve scripts for the mailbox configured with services . dovecot2 . imapsieve . mailbox . <name> . name when the message originates from the indicated mailbox .
This setting supports wildcards with a syntax compatible with the IMAP LIST command , meaning that this setting can apply to multiple or even all ( " * " ) mailboxes .
'' ;
example = " * " ;
type = types . nullOr types . str ;
} ;
causes = mkOption {
2024-02-07 01:22:34 +00:00
default = [ ] ;
2024-01-13 08:15:51 +00:00
description = ''
Only execute the administrator Sieve scripts for the mailbox configured with services . dovecot2 . imapsieve . mailbox . <name> . name when one of the listed IMAPSIEVE causes apply .
This has no effect on the user script , which is always executed no matter the cause .
'' ;
2024-02-07 01:22:34 +00:00
example = [ " C O P Y " " A P P E N D " ] ;
type = types . listOf ( types . enum [ " A P P E N D " " C O P Y " " F L A G " ] ) ;
2024-01-13 08:15:51 +00:00
} ;
before = mkOption {
default = null ;
description = ''
When an IMAP event of interest occurs , this sieve script is executed before any user script respectively .
This setting each specify the location of a single sieve script . The semantics of this setting is similar to sieve_before : the specified scripts form a sequence together with the user script in which the next script is only executed when an ( implicit ) keep action is executed .
'' ;
example = literalExpression " . / r e p o r t - s p a m . s i e v e " ;
type = types . nullOr types . path ;
} ;
after = mkOption {
default = null ;
description = ''
When an IMAP event of interest occurs , this sieve script is executed after any user script respectively .
This setting each specify the location of a single sieve script . The semantics of this setting is similar to sieve_after : the specified scripts form a sequence together with the user script in which the next script is only executed when an ( implicit ) keep action is executed .
'' ;
example = literalExpression " . / r e p o r t - s p a m . s i e v e " ;
type = types . nullOr types . path ;
} ;
} ;
} ) ) ;
} ;
sieve = {
plugins = mkOption {
default = [ ] ;
example = [ " s i e v e _ e x t p r o g r a m s " ] ;
description = " S i e v e p l u g i n s t o l o a d " ;
type = types . listOf types . str ;
} ;
extensions = mkOption {
default = [ ] ;
description = " S i e v e e x t e n s i o n s f o r u s e i n u s e r s c r i p t s " ;
example = [ " n o t i f y " " i m a p f l a g s " " v n d . d o v e c o t . f i l t e r " ] ;
type = types . listOf types . str ;
} ;
globalExtensions = mkOption {
default = [ ] ;
example = [ " v n d . d o v e c o t . e n v i r o n m e n t " ] ;
description = " S i e v e e x t e n s i o n s f o r u s e i n g l o b a l s c r i p t s " ;
type = types . listOf types . str ;
} ;
2024-02-07 01:22:34 +00:00
scripts = mkOption {
type = types . attrsOf types . path ;
default = { } ;
description = lib . mdDoc " S i e v e s c r i p t s t o b e e x e c u t e d . K e y i s a s e q u e n c e , e . g . ' b e f o r e 2 ' , ' a f t e r ' e t c . " ;
} ;
2024-01-13 08:15:51 +00:00
pipeBins = mkOption {
default = [ ] ;
example = literalExpression ''
map lib . getExe [
( pkgs . writeShellScriptBin " l e a r n - h a m . s h " " e x e c ' ' ${ pkgs . rspamd } / b i n / r s p a m c l e a r n _ h a m " )
( pkgs . writeShellScriptBin " l e a r n - s p a m . s h " " e x e c ' ' ${ pkgs . rspamd } / b i n / r s p a m c l e a r n _ s p a m " )
]
'' ;
description = " P r o g r a m s a v a i l a b l e f o r u s e b y t h e v n d . d o v e c o t . p i p e e x t e n s i o n " ;
type = types . listOf types . path ;
} ;
} ;
2020-04-24 23:36:52 +00:00
} ;
config = mkIf cfg . enable {
security . pam . services . dovecot2 = mkIf cfg . enablePAM { } ;
2022-01-23 02:10:13 +00:00
security . dhparams = mkIf ( cfg . sslServerCert != null && cfg . enableDHE ) {
2020-04-24 23:36:52 +00:00
enable = true ;
params . dovecot2 = { } ;
} ;
2024-01-13 08:15:51 +00:00
services . dovecot2 = {
protocols =
optional cfg . enableImap " i m a p "
++ optional cfg . enablePop3 " p o p 3 "
++ optional cfg . enableLmtp " l m t p " ;
mailPlugins = mkIf cfg . enableQuota {
globally . enable = [ " q u o t a " ] ;
perProtocol . imap . enable = [ " i m a p _ q u o t a " ] ;
} ;
sieve . plugins =
optional ( cfg . imapsieve . mailbox != [ ] ) " s i e v e _ i m a p s i e v e "
++ optional ( cfg . sieve . pipeBins != [ ] ) " s i e v e _ e x t p r o g r a m s " ;
sieve . globalExtensions = optional ( cfg . sieve . pipeBins != [ ] ) " v n d . d o v e c o t . p i p e " ;
2024-02-07 01:22:34 +00:00
pluginSettings = lib . mapAttrs ( n : lib . mkDefault ) ( {
sieve_plugins = concatStringsSep " " cfg . sieve . plugins ;
sieve_extensions = concatStringsSep " " ( map ( el : " + ${ el } " ) cfg . sieve . extensions ) ;
sieve_global_extensions = concatStringsSep " " ( map ( el : " + ${ el } " ) cfg . sieve . globalExtensions ) ;
sieve_pipe_bin_dir = sievePipeBinScriptDirectory ;
} // sieveScriptSettings // imapSieveMailboxSettings ) ;
2020-04-24 23:36:52 +00:00
} ;
users . users = {
dovenull =
{
uid = config . ids . uids . dovenull2 ;
description = " D o v e c o t u s e r f o r u n t r u s t e d l o g i n s " ;
group = " d o v e n u l l " ;
} ;
} // optionalAttrs ( cfg . user == " d o v e c o t 2 " ) {
dovecot2 =
{
uid = config . ids . uids . dovecot2 ;
description = " D o v e c o t u s e r " ;
group = cfg . group ;
} ;
} // optionalAttrs ( cfg . createMailUser && cfg . mailUser != null ) {
$ { cfg . mailUser } =
2021-04-17 00:35:05 +00:00
{ description = " V i r t u a l M a i l U s e r " ; isSystemUser = true ; } // optionalAttrs ( cfg . mailGroup != null )
2020-04-24 23:36:52 +00:00
{ group = cfg . mailGroup ; } ;
} ;
users . groups = {
dovenull . gid = config . ids . gids . dovenull2 ;
} // optionalAttrs ( cfg . group == " d o v e c o t 2 " ) {
dovecot2 . gid = config . ids . gids . dovecot2 ;
} // optionalAttrs ( cfg . createMailUser && cfg . mailGroup != null ) {
$ { cfg . mailGroup } = { } ;
} ;
environment . etc . " d o v e c o t / m o d u l e s " . source = modulesDir ;
environment . etc . " d o v e c o t / d o v e c o t . c o n f " . source = cfg . configFile ;
systemd . services . dovecot2 = {
description = " D o v e c o t I M A P / P O P 3 s e r v e r " ;
after = [ " n e t w o r k . t a r g e t " ] ;
wantedBy = [ " m u l t i - u s e r . t a r g e t " ] ;
2020-05-15 21:57:56 +00:00
restartTriggers = [ cfg . configFile modulesDir ] ;
2020-04-24 23:36:52 +00:00
2020-11-03 02:18:15 +00:00
startLimitIntervalSec = 60 ; # 1 min
2020-04-24 23:36:52 +00:00
serviceConfig = {
2021-08-23 08:02:39 +00:00
Type = " n o t i f y " ;
2020-04-24 23:36:52 +00:00
ExecStart = " ${ dovecotPkg } / s b i n / d o v e c o t - F " ;
ExecReload = " ${ dovecotPkg } / s b i n / d o v e a d m r e l o a d " ;
Restart = " o n - f a i l u r e " ;
RestartSec = " 1 s " ;
RuntimeDirectory = [ " d o v e c o t 2 " ] ;
} ;
# When copying sieve scripts preserve the original time stamp
# (should be 0) so that the compiled sieve script is newer than
# the source file and Dovecot won't try to compile it.
preStart = ''
2024-01-13 08:15:51 +00:00
rm - rf $ { stateDir } /sieve $ { stateDir } /imapsieve
2024-02-07 01:22:34 +00:00
'' + o p t i o n a l S t r i n g ( c f g . s i e v e . s c r i p t s ! = { } ) ''
2020-04-24 23:36:52 +00:00
mkdir - p $ { stateDir } /sieve
$ { concatStringsSep " \n " (
mapAttrsToList (
to : from : ''
if [ - d ' $ { from } ' ] ; then
mkdir ' $ { stateDir } /sieve / $ { to } '
cp - p " ${ from } / " * . sieve ' $ { stateDir } /sieve / $ { to } '
else
cp - p ' $ { from } ' ' $ { stateDir } /sieve / $ { to } '
fi
$ { pkgs . dovecot_pigeonhole } /bin/sievec ' $ { stateDir } /sieve / $ { to } '
''
2024-02-07 01:22:34 +00:00
) cfg . sieve . scripts
2020-04-24 23:36:52 +00:00
) }
chown - R ' $ { cfg . mailUser }: $ { cfg . mailGroup } ' ' $ { stateDir } /sieve '
2024-01-13 08:15:51 +00:00
''
+ optionalString ( cfg . imapsieve . mailbox != [ ] ) ''
mkdir - p $ { stateDir } /imapsieve / { before , after }
$ {
concatMapStringsSep " \n "
( el :
optionalString ( el . before != null ) ''
cp - p $ { el . before } $ { stateDir } /imapsieve/before / $ { baseNameOf el . before }
$ { pkgs . dovecot_pigeonhole } /bin/sievec ' $ { stateDir } /imapsieve/before / $ { baseNameOf el . before } '
''
+ optionalString ( el . after != null ) ''
cp - p $ { el . after } $ { stateDir } /imapsieve/after / $ { baseNameOf el . after }
$ { pkgs . dovecot_pigeonhole } /bin/sievec ' $ { stateDir } /imapsieve/after / $ { baseNameOf el . after } '
''
)
cfg . imapsieve . mailbox
}
$ {
optionalString ( cfg . mailUser != null && cfg . mailGroup != null )
" c h o w n - R ' ${ cfg . mailUser } : ${ cfg . mailGroup } ' ' ${ stateDir } / i m a p s i e v e ' "
}
2020-04-24 23:36:52 +00:00
'' ;
} ;
environment . systemPackages = [ dovecotPkg ] ;
2024-02-07 01:22:34 +00:00
warnings = warnAboutExtraConfigCollisions ;
2020-09-25 04:45:31 +00:00
2020-04-24 23:36:52 +00:00
assertions = [
{
assertion = ( cfg . sslServerCert == null ) == ( cfg . sslServerKey == null )
&& ( cfg . sslCACert != null -> ! ( cfg . sslServerCert == null || cfg . sslServerKey == null ) ) ;
message = " d o v e c o t n e e d s b o t h s s l S e r v e r C e r t a n d s s l S e r v e r K e y d e f i n e d f o r w o r k i n g c r y p t o " ;
}
{
assertion = cfg . showPAMFailure -> cfg . enablePAM ;
message = " d o v e c o t i s c o n f i g u r e d w i t h s h o w P A M F a i l u r e w h i l e e n a b l e P A M i s d i s a b l e d " ;
}
{
2024-02-07 01:22:34 +00:00
assertion = cfg . sieve . scripts != { } -> ( cfg . mailUser != null && cfg . mailGroup != null ) ;
message = " d o v e c o t r e q u i r e s m a i l U s e r a n d m a i l G r o u p t o b e s e t w h e n ` s i e v e . s c r i p t s ` i s s e t " ;
2020-04-24 23:36:52 +00:00
}
] ;
} ;
2024-01-13 08:15:51 +00:00
meta . maintainers = [ lib . maintainers . dblsaiko ] ;
2020-04-24 23:36:52 +00:00
}