Package: guix-patches;
Reported by: Joshua Branson <jbranso <at> dismail.de>
Date: Fri, 17 Jun 2022 21:47:01 UTC
Severity: normal
Tags: patch
Message #59 received at 56046 <at> debbugs.gnu.org (full text, mbox):
From: Joshua Branson <jbranso <at> dismail.de> To: Liliana Marie Prikler <liliana.prikler <at> gmail.com> Cc: Joshua Branson <joshua <at> gnucode.me>, 56046 <at> debbugs.gnu.org Subject: Re: [PATCH opensmtpd-records v3] services (opensmtpd): add opensmtpd records to enhance opensmtpd-configuration. Date: Tue, 27 Dec 2022 19:16:15 -0500
Liliana Marie Prikler <liliana.prikler <at> gmail.com> writes: > Am Freitag, dem 23.12.2022 um 08:52 -0500 schrieb Joshua Branson: >> >> * gnu/services/mail.scm: >> (opensmtpd-table, >> opensmtpd-ca, >> opensmtpd-pki, >> opensmtpd-action-local-delivery, >> opensmtpd-maildir, >> opensmtpd-mda, >> opensmtpd-lmtp, >> opensmtpd-relay, >> opensmtpd-option, >> opensmtpd-filter-phase, >> opensmtpd-filter, >> opensmtpd-interface, >> opensmtpd-socket, >> opensmtpd-match, >> opensmtpd-smtp, >> opensmtpd-srs, >> opensmtpd-queue, and >> opensmtpd-configuration): New records. > Don't forget to put closing parentheses at the end of lines. Also, > feel free to group them to save vertical space. Thanks again for your speedy review! I am sending this from my gnucode.me email address you'll notice. And it is using these new records. :) > >> (false?, is-value-right-type, add-comma-or-string, >> list-of-procedures->string, string-in-list?, my-sanitize, >> opensmtpd-filter-chain?, throw-error-duplicate-option, >> sanitize-list-of-options-for-match, sanitize-filters, >> list-has-duplicates-or-non-filters?, >> filter-phase-has-message-and-value?, >> filter-phase-decision-lacks-proper-message?, >> filter-phase-lacks-proper-value?, >> filter-phase-has-incorrect-junk-or-bypass?, >> filter-phase-junks-after-commit?, >> list-of-unique-filter-or-filter-phase?, throw-error, >> contains-duplicate?, list-of-type?, list-of-strings?, >> list-of-unique-opensmtpd-option?, >> list-of-opensmtpd-ca?, >> list-of-opensmtpd-pki?, >> list-of-opensmtpd-listen-on?, >> list-of-unique-opensmtpd-match?, list-of-strings->string, >> assoc-list? assoc-list, variable->string, >> tables-data-are-assoc-list?, >> tables-data-are-a-list-of-strings?, >> table-data-are-a-nested-list-of-strings?, >> assoc-list->string, >> opensmtpd-table->string, >> opensmtpd-listen-on->string, >> opensmtpd-listen-on-socket->string, >> opensmtpd-action-relay->string, >> opensmtpd-lmtp->string, >> opensmtpd-mda->string, >> opensmtpd-maildir->string, >> opensmtpd-action-local-delivery->string, >> opensmtpd-action->string, opensmtpd-option->string, >> opensmtpd-match->string, >> opensmtpd-ca->string, opensmtpd-pki->string, >> generate-filter-chain-name, opensmtpd-filter-chain->string, >> opensmtpd-filter-phase->string, opensmtpd-filters->string, >> opensmtpd-listen->string, >> opensmtpd-srs->string, >> opensmtpd-smtp->string, >> opensmtpd-queue->string, get-opensmtpd-actions, >> get-opensmtpd-pkis, get-opensmtpd-filters, flatten, >> get-opensmtpd-tables, opensmtpd-fieldname->string, >> list-of-records->string, opensmtpd->mixed-text-file): New >> procedures. >> >> * gnu/tests/mail.scm : new tests for various opensmtpd records. >> >> * doc/guix.texi (OpenSMTPD Service): Added documentation for the >> new records for opensmtpd. >> --- >> doc/guix.texi | 1065 ++++++++++++++++- >> gnu/services/mail.scm | 2560 >> ++++++++++++++++++++++++++++++++++++++++- >> gnu/tests/mail.scm | 713 ++++++++++++ >> 3 files changed, 4310 insertions(+), 28 deletions(-) >> >> diff --git a/doc/guix.texi b/doc/guix.texi >> index 535c8cdfc3..879a2ad233 100644 >> --- a/doc/guix.texi >> +++ b/doc/guix.texi >> @@ -25407,16 +25407,66 @@ could instantiate a dovecot service like >> this: >> @end lisp >> >> @subsubheading OpenSMTPD Service >> +@cindex opensmtpd >> >> @deffn {Scheme Variable} opensmtpd-service-type >> -This is the type of the @uref{https://www.opensmtpd.org, OpenSMTPD} >> -service, whose value should be an @code{opensmtpd-configuration} >> object >> -as in this example: >> +OpenSMTPD is an easy-to-use mail transfer agent (MTA). OpenSMTPD >> +@strong{listens} for incoming mail and @strong{matches} the mail to >> +@strong{actions}. The following records represent those stages: >> >> -@lisp >> -(service opensmtpd-service-type >> - (opensmtpd-configuration >> - (config-file (local-file "./my-smtpd.conf")))) >> +@multitable {aaaaaaaaa} >> {aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa} > I hope this will receive proper documentation. Users can still use (service opensmtpd-service-type (opensmtpd-configuration (config-file (local-file "./my-smtpd.conf")))) config-file is still a fieldname of <opensmtpd-configuration>. Is that what you mean? Also the generated documentation is available here: https://notabug.org/jbranso/linode-guix-system-configuration/src/master/opensmtpd-records-documentation.txt >> +@item @strong{listens} >> +@tab @code{<opensmtpd-interface>} >> +@item >> +@tab @code{<opensmtpd-socket>} >> +@item >> +@tab >> +@item @strong{matches} >> +@tab @code{<opensmtpd-match>} >> +@item >> +@tab >> +@item @strong{actions} >> +@tab @code{<opensmtpd-local-delivery>} >> +@item >> +@tab @code{<opensmtpd-relay>} >> +@end multitable >> + >> +Additionally, each @code{<opensmtpd-interface>} and >> +@code{<opensmtpd-socket>} may use a list of @code{<opensmtpd- >> filter>}, >> +and/or @code{<opensmtpd-filter-phase>} records to filter >> +email/spam. Also numerous records' fieldnames use >> +@code{<opensmtpd-table>} records to hold lists or key value pairs of >> +data. Be sure to read the @code{<opensmtpd-table>} section to learn >> the >> +differance between a @code{mapping table} and a @code{list table}. >> + >> +Finally, both @code{<opensmtpd-match>} and >> +@code{<opensmtpd-filter-phase>} use @code{<opensmtpd-option>} to >> +configure various options. >> + >> +A simple example opensmtpd configuration is below: >> + >> +@lisp >> +(let ((smtp.gnu.org (opensmtpd-pki >> + (domain "smtp.gnu.org") >> + (cert "file.cert") >> + (key "file.key")))) >> + (service opensmtpd-service-type >> + (opensmtpd-configuration >> + (interfaces (list >> + (opensmtpd-interface >> + (pki smtp.gnu.org)) >> + (opensmtpd-interface >> + (pki smtp.gnu.org) >> + (secure-connection "smtps")))) >> + (matches (list >> + (opensmtpd-match >> + (action >> + (opensmtpd-local-delivery >> + (name "local-delivery")))) >> + (opensmtpd-match >> + (action >> + (opensmtpd-relay >> + (name "relay"))))))))) >> @end lisp >> @end deffn >> >> @@ -25425,7 +25475,7 @@ Data type representing the configuration of >> opensmtpd. >> >> @table @asis >> @item @code{package} (default: @var{opensmtpd}) >> -Package object of the OpenSMTPD SMTP server. >> +Package object of the OpenSMTPD server. >> >> @item @code{config-file} (default: @code{%default-opensmtpd-config- >> file}) >> File-like object of the OpenSMTPD configuration file to use. By >> default >> @@ -25433,14 +25483,1013 @@ it listens on the loopback network >> interface, and allows for mail from >> users and daemons on the local machine, as well as permitting email >> to >> remote servers. Run @command{man smtpd.conf} for more information. >> >> +@item @code{bounce} (default: @code{(list "4h")}) >> +@code{bounce} is a list of strings, which send warning messages to >> the >> +envelope sender when temporary delivery failures cause a message to >> +remain in the queue for longer than a specified delay. Each delay >> option >> +is a string parameter beginning with a positive decimal integer and >> a >> +unit, which can be 's', 'm', 'h', or 'd'. At most four delay >> parameters >> +can be specified. >> + >> +@item @code{interfaces} default: >> +@lisp >> +(list >> + (opensmtpd-interface >> + (interface "lo") >> + (port 25))) >> +@end lisp >> +@code{interfaces} is a list of @code{<opensmtpd-interface>} records. >> +This list details what interfaces and ports OpenSMTPD listens on as >> well as >> +other options. >> + >> +@item @code{socket} (default: @code{(opensmtpd-socket)}) >> +Listens for incoming connections on the Unix domain socket. >> + >> +@item @code{includes} (default: @code{#f}) >> +@code{includes} is a list of string filenames. Each filename's >> contents is >> +additional configuration that is inserted into the top of the >> configuration >> +file. Run @code{man smtpd.conf} for more information. >> + >> +@item @code{matches} default: >> +@lisp >> +(list (opensmtpd-match >> + (action (opensmtpd-local-delivery >> + (name "local") >> + (method "mbox") >> + (options >> + (list >> + (opensmtpd-option >> + (option "for local"))))))) >> + (opensmtpd-match >> + (action (opensmtpd-relay >> + (name "outbound"))) >> + (options >> + (list >> + (opensmtpd-option >> + (option "from local")) >> + (opensmtpd-option >> + (option "for any")))))) >> +@end lisp >> +@code{matches} is a list of @code{<opensmtpd-match>} records, which >> +matches incoming mail and sends it to a correspending action. The >> match >> +records are evaluated sequentially, with the first match winning. >> +Therefore @emph{the order that you arrange your matches is >> important}. >> +It's a good idea to put specific matches first and an all >> emcompassing >> +match (like @code{(option "for any")}) @strong{last}. If an incoming >> +mail does not match any match records, then it is rejected. >> + >> +@item @code{mta-max-deferred} (default: @code{100}) >> +When delivery to a given host is suspended due to temporary >> failures, cache >> +at most number envelopes for that host such that they can be >> delivered as >> +soon as another delivery succeeds to that host. The default is 100. >> + >> +@item @code{queue} (default: @code{#f}) >> +@code{queue} expects an @code{<opensmtpd-queue>} record. With it, >> one may >> +compress and encrypt queue-ed emails as well as set the default >> expiration >> +time for temporarily undeliverable messages. >> + >> +@item @code{smtp} (default: @code{#f}) >> +@code{smtp} expects an @code{<opensmtpd-smtp>} record, which lets >> one >> +specifiy how large email may be along with other settings. >> + >> +@item @code{srs} (default: @code{#f}) >> +@code{srs} expects an @code{<opensmtpd-srs>} record, which lets one >> set >> +up SRS, the Sender Rewritting Scheme. >> + >> @item @code{setgid-commands?} (default: @code{#t}) >> Make the following commands setgid to @code{smtpq} so they can be >> executed: @command{smtpctl}, @command{sendmail}, @command{send- >> mail}, >> @command{makemap}, @command{mailq}, and @command{newaliases}. >> @xref{Setuid Programs}, for more information on setgid programs. >> + >> @end table >> @end deftp >> >> +@itemize >> +@item Data Type: opensmtpd-interface >> +Data type representing the configuration of an >> +@code{<opensmtpd-interface>}. It listens on the fieldname >> +@code{interface} for incoming connections, using the same syntax as >> +@code{ifconfig}. The interface parameter may also be an string >> interface >> +group, an string IP address, or a string domain name. Listening can >> +optionally be restricted to a specific address via the fieldname >> +@code{family}, which can be either @code{"inet4"} or @code{"inet6"}. >> + >> +@itemize >> +@item @code{interface} (default: @code{"lo"}) >> + >> +The string interface to listen for incoming connections. This >> string >> +may be an interface group, an IP address, or a domain name. These >> +interfaces can usually be found by the command @code{ip link}. >> + >> +@item @code{family} (default: @code{#f}) >> + >> +Only listen on a specific address family. Valid strings are >> +@code{"inet4"} or @code{"inet6"}, which will only listen on IPv4 or >> IPv6 >> +respectfully. If @code{(family #f)}, then opensmtpd will listen on >> both >> +IPv4 and IPv6. >> + >> +@item @code{auth} (default: @code{#f}) >> +Support SMTPAUTH: clients may only start SMTP transactions after >> +successful authentication. If @code{auth} is @code{#t}, then users >> are >> +authenticated against their own normal login credentials. >> Alternatively >> +@code{auth} may be a @code{mapping table} that maps usernames to >> +encrypted passwords. The password can be encrypted via the >> +@code{smtpctl} @code{encrypt} subcommand. >> + >> +@item @code{auth-optional} (default: @code{#f}) >> +Support SMTPAUTH optionally: clients need not authenticate, but may >> do >> +so. This allows the @code{<opensmtpd-interface>} to both accept >> +incoming mail from untrusted senders and permit outgoing mail from >> +authenticated users. It can be used in situations where it is not >> +possible to listen on a separate port (usually the submission port, >> 587) >> +for users to authenticate. This option also accepts a @code{mapping >> +table} that maps usernames to encrypted passwords. >> + >> +@item @code{filters} (default: @code{#f}) >> +A list of one or many @code{<opensmtpd-filter>} or >> +@code{<opensmtpd-filter-phase>} records. The filters are applied >> +sequentially. These records listen and filter on connections handled >> by this >> +listener. >> + >> +@item @code{hostname} (default: @code{#f}) >> +Change the default server name in the greeting banner instead of the >> +default one. >> + >> +@item @code{hostnames} (default: @code{#f}) >> +Override the server name for specific addresses. Use a @code{mapping >> +table} that maps string IP addresses to string hostnames. If the >> address >> +on which the connection arrives appears in the mapping, the >> associated >> +hostname is used. >> + >> +@item @code{mask-src} (default: @code{#f}) >> +If @code{#t}, then omit the from part when prepending “Received” >> headers. >> + >> +@item @code{disable-dsn} (default: @code{#f}) >> +When @code{#t}, then disable the DSN (Delivery Status Notification) >> extension. >> + >> +@item @code{pki} (default: @code{#f}) >> +For secure connections, use an @code{<opensmtpd-pki>} record to >> prove a >> +mail server's identity. >> + >> +@item @code{port} (default: @code{25}) >> +Listen on the integer port instead of the default port of 25. >> + >> +@item @code{proxy-v2} (default: @code{#f}) >> +If @code{#t}, then support the PROXYv2 protocol, rewriting >> appropriately source >> +address received from proxy. >> + >> +@item @code{received-auth} (default: @code{#f}) >> +If @code{#t}, then in “Received” headers, report whether the session >> was >> +authenticated and by which local user. >> + >> +@item @code{senders} (default: @code{#f}) >> +Look up the authenticated user in the supplied @code{mapping table} >> to >> +find the email addresses that user is allowed to submit mail as. >> + >> +@item @code{masquerade} (default: @code{#f}) >> +@code{masquerade}, is used in conjunction with @code{senders}. If >> +@code{#t}, then the From header is rewritten to match the sender >> +provided in the SMTP session. If @code{senders} is @code{#false}, >> then >> +@code{masquerade} cannot be @code{#t}. >> + >> +@item @code{secure-connection} (default: @code{#f}) >> +This is a string of one of these options: >> + >> +@multitable {aaaaaaaaaaaaaaaaaaaa} >> {aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa} > Same here Are you saying secure-connection is not documented? It's documented in the table just below: >> +@item @code{"smtps"} >> +@tab Support SMTPS, by default on port 465. >> +@item @code{"tls"} >> +@tab Support STARTTLS, by default on port 25. >> +@item @code{"tls-require"} >> +@tab Like @code{"tls"}, but force clients to >> +@item >> +@tab establish a secure connection before being >> +@item >> +@tab allowed to start an SMTP transaction. >> +@item @code{"tls-require-verify"} >> +@tab Like @code{"tls-require"}, but clients must >> +@item >> +@tab also provide a valid certificate >> +@item >> +@tab to establish an SMTP session. >> +@end multitable >> + >> +@item @code{tag} (default: @code{#f}) >> +Clients connecting to the listener are tagged with the given string >> tag. >> +@end itemize >> + >> +@item Data Type: opensmtpd-socket >> +Data type representing the configuration of an >> +@code{<opensmtpd-socket>}. Listen for incoming SMTP connections on >> the >> +Unix domain socket @samp{/var/run/smtpd.sock}. This is done by >> default, >> +even if the record is absent. >> + >> +@itemize >> +@item @code{filters} (default: @code{#f}) >> +A list of one or many @code{<opensmtpd-filter>} or >> +@code{<opensmtpd-filter-phase>} records. These filter incoming >> +connections handled by this listener. >> + >> +@item @code{mask-src} (default: @code{#f}) >> +If @code{#t}, then omit the from part when prepending “Received” >> headers. >> + >> +@item @code{tag} (default: @code{#f}) >> +Clients connecting to the listener are tagged with the given string >> tag. >> +@end itemize >> + >> +@item Data Type: opensmtpd-match >> +@cindex opensmtpd-match >> +This data type represents the configuration of an >> +@code{<opensmtpd-match>} record. >> + >> +If at least one mail envelope matches the options of one match >> record, >> +receive the incoming message, put a copy into each matching >> envelope, >> +and atomically save the envelopes to the mail spool for later >> processing >> +by the respective @code{<opensmtpd-action>} found in fieldname >> +@code{action}. Here is an example @code{opensmtpd-match} >> +record. >> + >> +@lisp >> +(opensmtpd-match >> + (action (opensmtpd-local-delivery >> + (name "receive") >> + (method (opensmtpd-maildir >> + (pathname "/home/%@{rcpt.user@}/Maildir") >> + (junk #t))) >> + (virtual (opensmtpd-table >> + (name "virt") >> + (data '(("carmen" . "carmen@@gnu.org"))))))) >> + (options (list (opensmtpd-option >> + (option "from any")) >> + (opensmtpd-option >> + (option "for domain") >> + (data (opensmtpd-table >> + (name "domain-table") >> + (data (list "gnu.org" "fsf.org")))))))) >> +@end lisp >> + >> +@itemize >> +@item @code{action} (default: @code{#f}) >> + >> +If mail matches this match configuration, then do this action. Valid >> values >> +include @code{<opensmtpd-local-delivery>} or >> +@code{<opensmtpd-relay>}. >> + >> +@item @code{options} (default: @code{#f}) >> +The fieldname @code{option} is a list of unique >> +@code{<opensmtpd-option>} records. >> + >> +There are some mutually exclusive options: there can be only one >> ``for'' >> +and only one ``from'' option. >> + >> +@multitable {aaaaaaaaaaaaaaaaaaaaaaaaa} >> {aaaaaaaaaaaaaaaaaaaaaaaaaaaaaa} > and here. If you are referring to <opensmtpd-option> is it documented like this: • Data Type: opensmtpd-option This data type represents the configuration of an ‘<opensmtpd-option>’, which is used by ‘<opensmtpd-filter-phase>’ and ‘<opensmtpd-match>’ to match various options for email. (sorry about the above formatting). That is currently how the documentation is generated. I need to go through the documentation is fix that. I did <opensmtpd-configuration> correctly. >> +@headitem for >> +@tab from >> +@item only use one of the following: >> +@tab only use one of the following: >> +@item @code{"for any"} >> +@tab @code{"from any"} >> +@item @code{"for local"} >> +@tab @code{"from auth"} >> +@item @code{"for domain"} >> +@tab @code{"from local"} >> +@item @code{"for rcpt-to"} >> +@tab @code{"from mail-from"} >> +@item >> +@tab @code{"from socket"} >> +@item >> +@tab @code{"from src"} >> +@end multitable >> + >> +Additionally, some options require additional data via >> +@code{<opensmtpd-option>}'s fieldname @code{data}. The following >> list >> +will explain the below syntax. >> + >> +@itemize >> +@item @code{"for any"} >> +This option only requires fieldname @code{option} to have the string >> +@code{"for any"}: >> + >> +@lisp >> + (opensmtpd-option >> + (option "for any")) >> +@end lisp >> + >> +@item @code{"tag"} _tag_ >> +This option only requires fieldname @code{option} to have the string >> +@code{"tag"} with a string in fieldname @code{data}: >> + >> +@lisp >> + (opensmtpd-option >> + (option "tag") >> + (data "this-tag")) >> +@end lisp >> + >> +@item @code{"for rcpt"} _domain_ | <list table> >> +This option requires fieldname @code{data} to have a string domain >> or >> +@code{list table}: >> + >> +@lisp >> + (opensmtpd-option >> + (option "for rcpt") >> + (data "gnu.org")) >> +@end lisp >> + >> +OR >> + >> +@lisp >> + (opensmtpd-option >> + (option "for rcpt") >> + (data (list "gnu.org" "fsf.org"))) >> +@end lisp >> +@end itemize >> + >> +The following matching options are supported and can all be negated >> (via not >> +#t). The options that support a table (anything surrounded with '<' >> and '>' >> +eg: <table>), also support specifying regex via (regex #t). >> + >> +@itemize >> +@item @code{"for any"} >> +Specify that session may address any destination. >> + >> +@item @code{"for local"} >> +Specify that session may address any local domain. This is the >> default, >> +and may be omitted. >> + >> +@item @code{"for domain"} _domain_ | <domain> >> +Specify that session may address the string _domain_ or >> +@code{list table} <domain>. >> + >> +@item @code{"for rcpt-to"} _recipient_ | <recipient> >> +Specify that session may address the string _recipient_ or list >> table >> +<recipient>. >> + >> +@item @code{"from any"} >> +Specify that session may originate from any source. >> + >> +@item @code{"from auth"} >> +Specify that session may originate from any authenticated user, no >> matter >> +the source IP address. >> + >> +@item @code{"from auth"} _user_ | <user> >> +Specify that the session may originate from authenticated _user_ or >> +@code{list table} <user>, no matter the source IP address. >> + >> +@item @code{"from local"} >> +Specify that session may only originate from a local IP address, or >> from >> +the local enqueuer. This is the default, and may be omitted. >> + >> +@item @code{"from mail-from"} _sender_ | <sender> >> +Specify that session may originate from _sender_ or @code{list >> table} >> +<sender>, no matter the source IP address. >> + >> +@item @code{"from rdns"} >> +Specify that session may only originate from an IP address that >> resolves >> +to a reverse DNS@. >> + >> +@item @samp{"from rdns"} _hostname_ | <hostname> >> +Specify that session may only originate from an IP address that >> resolves >> +to a reverse DNS matching string _hostname_ or @code{list table} >> +<hostname>. >> + >> +@item @samp{"from socket"} >> +Specify that session may only originate from the local enqueuer. >> + >> +@item @code{"from src"} _address_ | <address> >> +Specify that session may only originate from string _address_ or >> +@code{list table} <address> which can be a specific address or a >> subnet >> +expressed in CIDR-notation. >> + >> +@item @code{"auth"} >> +Matches transactions which have been authenticated. >> + >> +@item @code{"auth"} _username_ | <username> >> +Matches transactions which have been authenticated for string _user_ >> or >> +@code{list table} <username>. >> + >> +@item @code{"helo"} _helo-name_ | <helo-name> >> +Specify that session's HELO / EHLO should match the string _helo- >> name_ >> +or @code{list table} <helo-name>. >> + >> +@item @code{"mail-from"} _sender_ | <sender> >> +Specify that transactions's MAIL FROM should match the string >> _sender_ >> +or @code{list table} <sender>. >> + >> +@item @code{"rcpt-to"} _recipient_ | <recipient> >> +Specify that transaction's RCPT TO should match the string >> _recipient_ >> +or @code{list table} <recipient>. >> + >> +@item @code{"tag"} _tag_ >> +Matches transactions tagged with the given tag. >> + >> +@item @code{"tls"} >> +Specify that transaction should take place in a TLS channel. >> +@end itemize >> + >> +@end itemize >> + >> +@item Data Type: opensmtpd-local-delivery >> +This data type represents the configuration of an >> +@code{<opensmtpd-local-delivery>} record. >> + >> +@itemize >> +@item @code{name} (default: @code{#f}) >> +@code{name} is the string name of the relay action. >> + >> +@item @code{method} (default: @code{"mbox"}) >> +The email delivery option. Valid options are: >> + >> +@itemize >> +@item @code{"mbox"} >> +Deliver the message to the user's mbox with mail.local(8). >> + >> +@item @code{"expand-only"} >> +Only accept the message if a delivery method was specified in an >> aliases >> +or .forward file. >> + >> +@item @code{"forward-only"} >> +Only accept the message if the recipient results in a remote address >> after >> +the processing of aliases or forward file. >> + >> +@item @code{<opensmtpd-lmtp>} >> +Deliver the message to an LMTP server at @code{<opensmtpd-lmtp>}'s >> +fieldname @code{destination}. The location may be expressed as >> string >> +host:port or as a UNIX socket. Optionally, @code{<opensmtpd-lmtp>}'s >> +fieldname @code{rcpt-to} might be specified to use the recipient >> email >> +address (after expansion) instead of the local user in the LMTP >> session >> +as RCPT TO. >> + >> +@item @code{<opensmtpd-maildir>} >> +Deliver the message to the maildir in >> +@code{<opensmtpd-maildir>}'s fieldname @code{pathname} if specified, >> +or by default to @code{"~/Maildir"}. >> + >> +The pathname may contain format specifiers that are expanded before >> use >> +(see the below section about Format Specifiers). >> + >> +If @code{<opensmtpd-maildir>}'s record fieldname @code{junk} is >> @code{#t}, >> +then message will be moved to the ‘Junk’ folder if it contains a >> positive >> +‘X-Spam’ header. This folder will be created under fieldname >> @code{pathname} if >> +it does not yet exist. >> + >> +@item @code{<opensmtpd-mda>} >> +Delegate the delivery to the @code{<opensmtpd-mda>}'s fieldname >> +@code{command} (type string) that receives the message on its >> standard input. >> + >> +The @code{command} may contain format specifiers that are expanded >> before use >> +(see Format Specifiers). >> +@end itemize >> + >> +@item @code{alias} (default: @code{#f}) >> +Use the @code{mapping table} for aliases expansion. >> + >> +@item @code{ttl} (default: @code{#f}) >> +@code{ttl} is a string specify how long a message may remain in the >> queue. It's >> +format is @code{n@{s|m|h|d@}}. eg: @code{"4m"} is four minutes. >> + >> +@item @code{user} (default: @code{#f} ) >> +@code{user} is the string username for performing the delivery, to >> be looked up >> +with getpwnam(3). >> + >> +This is used for virtual hosting where a single username is in >> charge of >> +handling delivery for all virtual users. >> + >> +This option is not usable with the mbox delivery method. >> + >> +@item @code{userbase} (default: @code{#f}) >> +@code{userbase} is an @code{<opensmtpd-table>} record for mapping >> user >> +lookups instead of the getpwnam(3) function. >> + >> +The fieldnames @code{user} and @code{userbase} are mutually >> exclusive. >> + >> +@item @code{virtual} (default: @code{#f}) >> +@code{virtual} is an @code{<opensmtpd-table>} record is used for >> virtual >> +expansion. >> +@end itemize >> + >> +@item Data Type: opensmtpd-relay >> +This data type represents the configuration of an >> +@code{<opensmtpd-relay>} record. >> + >> +@itemize >> +@item @code{name} (default: @code{#f}) >> +@code{name} is the string name of the relay action. >> + >> +@item @code{backup} (default: @code{#f}) >> +When @code{#t}, operate as a backup mail exchanger delivering >> messages to any >> +mail exchanger with higher priority. >> + >> +@item @code{backup-mx} (default: @code{#f}) >> +Operate as a backup mail exchanger delivering messages to any mail >> exchanger >> +with higher priority than mail exchanger identified as string name. >> + >> +@item @code{helo} (default: @code{#f}) >> +Advertise string heloname as the hostname to other mail exchangers >> during >> +the HELO phase. >> + >> +@item @code{helo-src} (default: @code{#f} ) >> + Use the mapping @code{<opensmtpd-table>} to look up a hostname >> +matching the source address, to advertise during the HELO phase. >> + >> +@item @code{domain} (default: @code{#f}) >> +Do not perform MX lookups but look up destination domain in an >> +@code{<opensmtpd-table>} and use matching relay url as relay host. >> + >> +@item @code{host} (default: @code{#f}) >> +Do not perform MX lookups but relay messages to the relay host >> described by >> +the string relay-url. The format for relay-url is >> +@samp{[proto://[label@@]]host[:port]}. The following protocols are >> available: >> + >> +@multitable {aaaaaaaaaa} >> {aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa} > AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA. Are you giving me a triple A+ ? :) Org generated the the like that. I think you mentioned that I should use fractions last time. Sorry I did not do that. If I wait 'til I implement every one of your suggestions, I will probably never submit it. I am really probably "perfecting" this service. >> +@item @code{smtp} >> +@tab Normal SMTP session with opportunistic STARTTLS (the default). >> +@item @code{smtp+tls} >> +@tab Normal SMTP session with mandatory STARTTLS@. >> +@item @code{smtp+notls} >> +@tab Plain text SMTP session without TLS@. >> +@item @code{lmtp} >> +@tab LMTP session. port is required. >> +@item @code{smtps} >> +@tab SMTP session with forced TLS on connection, default port is >> +@item >> +@tab 465. >> +@end multitable >> + >> +Unless noted, port defaults to 25. >> + >> +The label corresponds to an entry in a credentials table, as >> documented in >> +@code{man table}. It is used with the @code{"smtp+tls"} and >> @code{"smtps"} protocols for >> +authentication. Server certificates for those protocols are verified >> by >> +default. >> + >> +@item @code{pki} (default: @code{#f}) >> +For secure connections, use the certificate associated with >> +@code{<opensmtpd-pki>} (declared in a pki directive) to prove the >> +client's identity to the remote mail server. >> + >> +@item @code{srs} (default: @code{#f}) >> +If @code{#t}, then when relaying a mail resulting from a forward, >> use the Sender >> +Rewriting Scheme to rewrite sender address. >> + >> +@item @code{tls} (default: @code{#f}) boolean or string ``no- >> verify'' > Instead of a string, take 'no-verify as symbol perhaps? Sounds good to me. May I ask why you prefer a symbol instead of a string? >> +When @code{#t}, Require TLS to be used when relaying, using >> mandatory STARTTLS by >> +default. When used with a smarthost, the protocol must not be >> +@samp{"smtp+notls://"}. When string @code{"no-verify"}, then do not >> require a valid >> +certificate. >> + >> +@item @code{auth} (default: @code{#f}) @code{<opensmtpd-table>} >> +Use the alist @code{<opensmtpd-table>} for connecting to relay-url >> +using credentials. This option is usable only with fieldname >> @code{host} option. >> + >> +@item @code{mail-from} (default: @code{#f}) string >> +Use the string mailaddress as MAIL FROM address within the SMTP >> transaction. >> + >> +@item @code{src} (default: @code{#f}) string | @code{<opensmtpd- >> table>} >> +Use the string or @code{<opensmtpd-table>} sourceaddr for the >> +source IP address, which is useful on machines with multiple >> interfaces. If >> +the list contains more than one address, all of them are used in >> such a way >> +that traffic is routed as efficiently as possible. >> +@end itemize >> + >> +@item Data Type: opensmtpd-filter >> +This data type represents the configuration of an >> +@code{<opensmtpd-filter>}. This is the filter record one should use >> +if they want to use an external package to filter email eg: rspamd >> or >> +spamassassin. >> + >> +@itemize >> +@item @code{name} (default: @code{#f}) >> +The string name of the filter. >> + >> +@item @code{proc} (default: @code{#f}) >> +The string command or process name. If @code{proc-exec} is >> @code{#t}, @code{proc} is >> +treated as a command to execute. Otherwise, it is a process name. >> + >> +@item @code{proc-exec} (default: @code{#f}) >> +If @code{#t}, then execute the command in @code{proc}. >> +@end itemize >> + >> +@item Data Type: opensmtpd-filter-phase >> +This data type represents the configuration of an >> +@code{<opensmtpd-filter-phase>}. >> + >> +In a regular workflow, @code{smtpd(8)} may accept or reject a >> message >> +based only on the content of envelopes. Its decisions are about the >> +handling of the message, not about the handling of an active >> session. >> + >> +Filtering extends the decision making process by allowing >> +@code{smtpd(8)} to stop at each phase of an SMTP session, check that >> +options are met, then decide if a session is allowed to move >> forward. >> + >> +With filtering via an @code{<opensmtpd-filter-phase>} record, a >> +session may be interrupted at any phase before an envelope is >> complete. A >> +message may also be rejected after being submitted, regardless of >> whether the >> +envelope was accepted or not. >> + >> +@itemize >> +@item @code{name} (default: @code{#f}) >> + >> +The string name of the filter phase. >> + >> +@item @code{phase-name} (default: @code{#f}) >> +The string name of the phase. Valid values are: >> + >> +@multitable {aaaaaaaaaaa} >> {aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa} >> +@item @code{"connect"} >> +@tab upon connection, before a banner is displayed >> +@item @code{"helo"} >> +@tab after HELO command is submitted >> +@item @code{"ehlo"} >> +@tab after EHLO command is submitted >> +@item @code{"mail-from"} >> +@tab after MAIL FROM command is submitted >> +@item @code{"rcpt-to"} >> +@tab after RCPT TO command is submitted >> +@item @code{"data"} >> +@tab after DATA command is submitted >> +@item @code{"commit"} >> +@tab after message is fully is submitted >> +@end multitable >> + >> +@item @code{options} (default @code{#f}) >> +A list of unique @code{<opensmtpd-option>} records. >> + >> +At each phase, various options, specified by a list of >> +@code{<opensmtpd-option>}, may be checked. The >> +@code{<opensmtpd-option>}'s fieldname @code{option} values of: >> +@code{"fcrdns"}, @code{"rdns"}, and @code{"src"} data are available >> in >> +all phases, but other data must have been already submitted before >> they >> +are available. Options with a @code{<table>} next to them require >> the >> +@code{<opensmtpd-option>}'s fieldname @code{data} to be an >> +@code{<opensmtpd-table>}. There are the available options: >> + >> +@multitable {aaaaaaaaaaaaaaaaaaaaaaaaa} >> {aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa} >> +@item @code{"fcrdns"} >> +@tab forward-confirmed reverse DNS is valid >> +@item @code{"rdns"} >> +@tab session has a reverse DNS >> +@item @code{"rdns"} <table> >> +@tab session has a reverse DNS in table >> +@item @code{"src"} <table> >> +@tab source address is in table >> +@item @code{"helo"} <table> >> +@tab helo name is in table >> +@item @code{"auth"} >> +@tab session is authenticated >> +@item @code{"auth"} <table> >> +@tab session username is in table >> +@item @code{"mail-from"} <table> >> +@tab sender address is in table >> +@item @code{"rcpt-to"} <table> >> +@tab recipient address is in table >> +@end multitable >> + >> +These conditions may all be negated by setting >> +@code{(opensmtpd-option (bool #f))}. >> + >> +Any conditions that require a table may indicate that tables include >> regexs >> +setting @code{(opensmtpd-option (regex #t))}. >> + >> +@item @code{decision} >> +A string decision to be taken. Some decisions require an >> @code{message} >> +or @code{value}. The value and message may be put in the >> +@code{<opensmtpd-option>}'s fieldname @code{data}. Valid strings >> are: >> + >> +@multitable {aaaaaaaaaaaaaaaaaaaaaa} >> {aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa} >> +@item @code{"bypass"} >> +@tab the session or transaction bypasses filters >> +@item @code{"disconnect"} message >> +@tab the session is disconnected with message >> +@item @code{"junk"} >> +@tab the session or transaction is junked, >> +@item >> +@tab i.e., an ‘X-Spam: yes’ header is added to >> +@item >> +@tab any messages >> +@item @code{"reject"} message >> +@tab the command is rejected with message >> +@item @code{"rewrite"} value >> +@tab the command parameter is rewritten with value >> +@end multitable >> + >> +Decisions that involve a message require that the message be RFC >> valid, >> +meaning that they should either start with a 4xx or 5xx status code. >> +Descisions can be taken at any phase, though junking can only happen >> before >> +a message is committed. >> + >> +@item @code{message} (default @code{#f}) >> +A string message beginning with a 4xx or 5xx status code. >> + >> +@item @code{value} (default: @code{#f}) >> +A number value. @code{value} and @code{message} are mutually >> exclusive. >> +@end itemize >> + >> +@item Data Type: opensmtpd-option >> +This data type represents the configuration of an >> +@code{<opensmtpd-option>}, which is used by >> +@code{<opensmtpd-filter-phase>} and @code{<opensmtpd-match>} >> +to match various options for email. >> + >> +@itemize >> +@item @code{option} (default @code{#f}) string >> + >> +A string option to be taken. Some options require the fieldname >> +@code{data} to have a string or an @code{<opensmtpd-table>}. When >> the >> +option record is used inside of an @code{<opensmtpd-filter-phase>}, >> then >> +valid strings for fieldname @code{option} are: >> + >> +@itemize >> +@item @code {"fcrdns"} >> +@item @code {"rdns"} >> +@item @code {"src"} >> +@item @code {"helo"} >> +@item @code {"auth"} >> +@item @code {"mail-from"} >> +@item @code {"rcpt-to"} >> +@end itemize >> + >> +When @code{<opensmtpd-option>} is used inside of an >> +@code{<opensmtpd-match>}, then valid strings for fieldname >> @code{option} >> +are: >> + >> +@itemize >> +@item @code {"for"} >> +@item @code {"for any"} >> +@item @code {"for local"} >> +@item @code {"for domain"} >> +@item @code {"for rcpt-to"} >> +@item @code {"from any"} >> +@item @code {"from auth"} >> +@item @code {"from local"} >> +@item @code {"from mail-from"} >> +@item @code {"from rdns"} >> +@item @code {"from socket"} >> +@item @code {"from src"} >> +@item @code {"auth"} >> +@item @code {"helo"} >> +@item @code {"mail-from"} >> +@item @code {"rcpt-to"} >> +@item @code {"tag"} >> +@item @code {"tls"} >> +@end itemize >> + >> +@item @code{data} (default @code{#f}) string | @code{<opensmtpd- >> table>} >> +Some options require a string or @code{<opensmtpd-table>} to be >> +present. One would specify that table here. >> + >> +@item @code{regex} (default: @code{#f}) boolean >> +Any options using a table may indicate that tables hold regular >> +expressions by setting this option to @code{#t}. >> + >> +@item @code{bool} (default: @code{#t}) boolean >> +When @code{(bool #f)}, this option record is negated. >> +@end itemize >> + >> +@item Data Type: opensmtpd-table >> +This data type represents the configuration of an >> +@code{<opensmtpd-table>}. >> + >> +@itemize >> +@item @code{name} (default @code{#f}) >> +@code{name} is the name of the @code{<opensmtpd-table>} record. >> + >> +@item @code{data} (default: @code{#f}) string | list | alist | >> nested-list >> +@code{data} expects a string, a list of strings, an alist of >> strings, or >> +a nested list of strings. >> +eg: >> + >> +@itemize >> + >> +@item string >> +@lisp >> +(data "dev@@gnu.org") >> +@end lisp >> + >> +A table of this type is called a @code{string table}. >> + >> +@item list >> +@lisp >> +(data (list ("gnu.org" "fsf.org"))) >> +@end lisp >> + >> +A table of this type is called a @code{list table}. >> + >> +@item alist >> +@lisp >> +(data '(("james" . "$encryptedPassword") >> + ("jennifer" . "$encryptedPassword2))) >> +@end lisp >> + >> +A table of this type is called a @code{mapping table}. >> + >> +@item nested-list >> +@lisp >> +(data '(("user1" "root@@gnu.org" "admin@@gnu.org") >> + ("user2" "james@@guix.gnu.org" "sarah@@fsf.org"))) >> +@end lisp >> + >> +A table of this type is also called a @code{mapping table}. >> + >> +@end itemize >> +@end itemize >> + >> +@item Data Type: opensmtpd-pki >> +This data type represents the configuration of an >> +@code{<opensmtpd-pki>}. >> + >> +@itemize >> +@item @code{domain} (default @code{#f}) >> +@code{domain} is the string name of the @code{<opensmtpd-pki>} >> record. >> + >> +@item @code{cert} (default: @code{#f}) >> +@code{cert} (default: @code{#f}) >> + >> +@code{cert} is the string certificate filename to use for this pki. >> + >> +@item @code{key} (default: @code{#f}) >> +@code{key} is the string certificate falename to use for this pki. >> + >> +@item @code{dhe} (default: @code{"none"}) >> +Specify the DHE string parameter to use for DHE cipher suites with >> host >> +pkiname. Valid parameter values are @code{"none"}, @code{"legacy"}, >> or >> +@code{"auto"}. For @code{"legacy"}, a fixed key length of 1024 bits >> is >> +used, whereas for @code{"auto"}, the key length is determined >> +automatically. The default is @code{"none"}, which disables DHE >> cipher >> +suites. >> +@end itemize >> + >> +@item Data Type: opensmtpd-maildir >> +@itemize >> +@item @code{pathname} (default: @code{"~/Maildir"}) >> +Deliver the message to the maildir if pathname if specified, or by >> default >> +to @code{"~/Maildir"}. >> + >> +The pathname may contain format specifiers that are expanded before >> use >> +(see FORMAT SPECIFIERS). >> + >> +@item @code{junk} (default: @code{#f}) >> +If the junk argument is @code{#t}, then the message will be moved to >> the @samp{‘Junk’} >> +folder if it contains a positive @samp{‘X-Spam’} header. This folder >> will be >> +created under pathname if it does not yet exist. >> +@end itemize >> + >> +@item Data Type: opensmtpd-mda >> +This record lets you delegate the delivery to a command that >> receives >> +the message on its standard input. >> + >> +@itemize >> +@item @code{name} >> +The string name for this MDA command. >> + >> +@item @code{command} >> +The command to that delivers the mail. >> + >> +The command may contain format specifiers that are expanded before >> use (see >> +FORMAT SPECIFIERS). >> +@end itemize >> + >> +@item Data Type: opensmtpd-queue >> +@itemize >> +@item @code{compression} (default @code{#f}) >> +Store queue files in a compressed format. This may be useful to save >> disk >> +space. >> + >> +@item @code{encryption} (default @code{#f}) >> +Encrypt queue files with EVP <at> math{_aes}@math{_256}@math{_gcm}(3). If >> no key is specified, it is >> +read with getpass(3). If the string stdin or a single dash (‘-’) is >> given >> +instead of a key, the key is read from the standard input. >> + >> +@item @code{ttl-delay} (default @code{#f}) >> +Set the default expiration time for temporarily undeliverable >> messages, >> +given as a positive decimal integer followed by a unit s, m, h, or >> d. The >> +default is four days (@code{"4d"}). >> +@end itemize >> + >> +@item Data Type: opensmtpd-smtp >> +Data type representing an @code{<opensmtpd-smtp>} record. >> + >> +@itemize >> +@item @code{ciphers} (default: @code{#f}) >> +Set the control string for >> SSL <at> math{_CTX}@math{_set}@math{_cipher}@math{_list}(3). The default >> is >> + ``HIGH:!aNULL:!MD5''. >> + >> +@item @code{limit-max-mails} (default: @code{100}) >> +Limit the number of messages to count for each sessio >> + >> +@item @code{limit-max-rcpt} (default: @code{1000}) >> +Limit the number of recipients to count for each transaction. >> + >> +@item @code{max-message-size} (default: @code{35M}) >> +Reject messages larger than size, given as a positive number of >> bytes or as >> +a string to be parsed with scan <at> math{_scaled}(3). >> + >> +@item @code{sub-addr-delim character} (default: @code{+}) >> +When resolving the local part of a local email address, ignore the >> ASCII >> +character and all characters following it. This is helpful for email >> +filters. @samp{"admin+bills@@gnu.org"} is the same email address as >> +@samp{"admin@@gnu.org"}. BUT an email filter can filter emails >> addressed to first >> +email address into a 'Bills' email folder. >> +@end itemize >> + >> +@item Data Type: opensmtpd-srs >> +Use this record to set up the Sender Rewriting Scheme (SRS). >> + >> +@itemize >> +@item @code{key} (default: @code{#f}) >> +Set the secret key to use for SRS, the Sender Rewriting Scheme. >> + >> +@item @code{backup-key} (default: @code{#f}) >> +Set a backup secret key to use as a fallback for SRS@. This can be >> used to >> +implement SRS key rotation. >> + >> +@item @code{ttl-delay} (default: @code{"4d"}) >> +Set the time-to-live delay for SRS envelopes. After this delay, a >> bounce >> +reply to the SRS address will be discarded to limit risks of forged >> +addresses. >> +@end itemize >> + >> +@item Format Specifiers >> +Some configuration records support expansion of their parameters at >> +runtime. Such records (for example >> +@code{<opensmtpd-maildir>}, @code{<opensmtpd-mda>}) may use >> +format specifiers which are expanded before delivery or relaying. >> The >> +following formats are currently supported: >> + >> +@multitable {aaaaaaaaaaaaaaaaaaa} >> {aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa} >> +@item @samp{%@{sender@}} >> +@tab sender email address, may be empty string >> +@item @samp{%@{sender.user@}} >> +@tab user part of the sender email address, may be empty >> +@item @samp{%@{sender.domain@}} >> +@tab domain part of the sender email address, may be empty >> +@item @samp{%@{rcpt@}} >> +@tab recipient email address >> +@item @samp{%@{rcpt.user@}} >> +@tab user part of the recipient email address >> +@item @samp{%@{rcpt.domain@}} >> +@tab domain part of the recipient email address >> +@item @samp{%@{dest@}} >> +@tab recipient email address after expansion >> +@item @samp{%@{dest.user@}} >> +@tab user part after expansion >> +@item @samp{%@{dest.domain@}} >> +@tab domain part after expansion >> +@item @samp{%@{user.username@}} >> +@tab local user >> +@item @samp{%@{user.directory@}} >> +@tab home directory of the local user >> +@item @samp{%@{mbox.from@}} >> +@tab name used in mbox From separator lines >> +@item @samp{%@{mda@}} >> +@tab mda command, only available for mda wrappers >> +@end multitable >> + >> +Expansion formats also support partial expansion using the optional >> bracket notations >> +with substring offset. For example, with recipient domain >> @samp{“example.org”}: >> + >> +@multitable {aaaaaaaaaaaaaaaaaaaaaa} {aaaaaaaaaaaaaaaaaaaa} >> +@item @samp{%@{rcpt.domain[0]@}} >> +@tab expands to “e” >> +@item @samp{%@{rcpt.domain[1]@}} >> +@tab expands to “x” >> +@item @samp{%@{rcpt.domain[8:]@}} >> +@tab expands to “org” >> +@item @samp{%@{rcpt.domain[-3:]@}} >> +@tab expands to “org” >> +@item @samp{%@{rcpt.domain[0:6]@}} >> +@tab expands to “example” >> +@item @samp{%@{rcpt.domain[0:-4]@}} >> +@tab expands to “example” >> +@end multitable >> + >> +In addition, modifiers may be applied to the token. For example, >> with recipient >> +@samp{“User+Tag@@Example.org”}: >> + >> +@multitable {aaaaaaaaaaaaaaaaaaaaaaaa} >> {aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa} >> +@item @samp{%@{rcpt:lowercase@}} >> +@tab expands to “user+tag@@example.org” >> +@item @samp{%@{rcpt:uppercase@}} >> +@tab expands to “USER+TAG@@EXAMPLE.ORG” >> +@item @samp{%@{rcpt:strip@}} >> +@tab expands to “User@@Example.org” >> +@item @samp{%@{rcpt:lowercasestrip@}} >> +@tab expands to “user@@example.org” >> +@end multitable >> + >> +For security concerns, expanded values are sanitized and potentially >> dangerous >> +characters are replaced with ‘:’. In situations where they are >> desirable, the >> +“raw” modifier may be applied. For example, with recipient >> +@samp{“user+t?g@@example.org”}: >> + >> +@multitable {aaaaaaaaaaaaa} {aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa} >> +@item @samp{%@{rcpt@}} >> +@tab expands to “user+t:g@@example.org” >> +@item @samp{%@{rcpt:raw@}} >> +@tab expands to “user+t?g@@example.org” >> +@end multitable >> +@end itemize >> + >> @subsubheading Exim Service >> >> @cindex mail transfer agent (MTA) >> diff --git a/gnu/services/mail.scm b/gnu/services/mail.scm >> index 43f144a42d..4175cab375 100644 >> --- a/gnu/services/mail.scm >> +++ b/gnu/services/mail.scm >> @@ -35,6 +35,10 @@ (define-module (gnu services mail) >> #:use-module (gnu packages admin) >> #:use-module (gnu packages dav) >> #:use-module (gnu packages tls) >> + #:use-module (guix i18n) >> + #:use-module (guix diagnostics) >> + #:use-module (guix ui) >> + #:use-module (guix utils) >> #:use-module (guix records) >> #:use-module (guix packages) >> #:use-module (guix gexp) >> @@ -58,10 +62,149 @@ (define-module (gnu services mail) >> mailbox-configuration >> namespace-configuration >> >> + opensmtpd-table >> + opensmtpd-table? >> + opensmtpd-table-name >> + opensmtpd-table-data >> + >> + opensmtpd-ca >> + opensmtpd-ca? >> + opensmtpd-ca-name >> + opensmtpd-ca-file >> + >> + opensmtpd-pki >> + opensmtpd-pki? >> + opensmtpd-pki-domain >> + opensmtpd-pki-cert >> + opensmtpd-pki-key >> + opensmtpd-pki-dhe >> + >> + opensmtpd-local-delivery >> + opensmtpd-local-delivery? >> + opensmtpd-local-delivery-method >> + opensmtpd-local-delivery-alias >> + opensmtpd-local-delivery-ttl >> + opensmtpd-local-delivery-user >> + opensmtpd-local-delivery-userbase >> + opensmtpd-local-delivery-virtual >> + opensmtpd-local-delivery-wrapper >> + >> + opensmtpd-maildir >> + opensmtpd-maildir? >> + opensmtpd-maildir-pathname >> + opensmtpd-maildir-junk >> + >> + opensmtpd-mda >> + opensmtpd-mda-name >> + opensmtpd-mda-command >> + >> + opensmtpd-lmtp >> + opensmtpd-lmtp-destination >> + opensmtpd-lmtp-rcpt >> + >> + opensmtpd-relay >> + opensmtpd-relay? >> + opensmtpd-relay-name >> + opensmtpd-relay-backup >> + opensmtpd-relay-backup-mx >> + opensmtpd-relay-helo >> + opensmtpd-relay-domain >> + opensmtpd-relay-host >> + opensmtpd-relay-pki >> + opensmtpd-relay-srs >> + opensmtpd-relay-tls >> + opensmtpd-relay-auth >> + opensmtpd-relay-mail-from >> + opensmtpd-relay-src >> + >> + opensmtpd-option >> + opensmtpd-option? >> + opensmtpd-option-option >> + opensmtpd-option-bool >> + opensmtpd-option-regex >> + opensmtpd-option-data >> + >> + opensmtpd-filter-phase >> + opensmtpd-filter-phase? >> + opensmtpd-filter-phase-name >> + opensmtpd-filter-phase-phase >> + opensmtpd-filter-phase-options >> + opensmtpd-filter-phase-decision >> + opensmtpd-filter-phase-message >> + opensmtpd-filter-phase-value >> + >> + opensmtpd-filter >> + opensmtpd-filter? >> + opensmtpd-filter-name >> + opensmtpd-filter-proc >> + >> + opensmtpd-interface >> + opensmtpd-interface? >> + opensmtpd-interface-interface >> + opensmtpd-interface-family >> + opensmtpd-interface-auth >> + opensmtpd-interface-auth-optional >> + opensmtpd-interface-filters >> + opensmtpd-interface-hostname >> + opensmtpd-interface-hostnames >> + opensmtpd-interface-mask-src >> + opensmtpd-interface-disable-dsn >> + opensmtpd-interface-pki >> + opensmtpd-interface-port >> + opensmtpd-interface-proxy-v2 >> + opensmtpd-interface-received-auth >> + opensmtpd-interface-senders >> + opensmtpd-interface-masquerade >> + opensmtpd-interface-secure-connection >> + opensmtpd-interface-tag >> + >> + opensmtpd-socket >> + opensmtpd-socket? >> + opensmtpd-socket-filters >> + opensmtpd-socket-mask-src >> + opensmtpd-socket-tag >> + >> + opensmtpd-match >> + opensmtpd-match? >> + opensmtpd-match-action >> + opensmtpd-match-options >> + >> + opensmtpd-smtp >> + opensmtpd-smtp? >> + opensmtpd-smtp-ciphers >> + opensmtpd-smtp-limit-max-mails >> + opensmtpd-smtp-limit-max-rcpt >> + opensmtpd-smtp-max-message-size >> + opensmtpd-smtp-sub-addr-delim character >> + >> + opensmtpd-srs >> + opensmtpd-srs? >> + opensmtpd-srs-key >> + opensmtpd-srs-backup-key >> + opensmtpd-srs-ttl-delay >> + >> + opensmtpd-queue >> + opensmtpd-queue? >> + opensmtpd-queue-compression >> + opensmtpd-queue-encryption >> + opensmtpd-queue-ttl-delay >> + >> opensmtpd-configuration >> opensmtpd-configuration? >> + opensmtpd-package >> + opensmtpd-config-file >> + opensmtpd-configuration-bounce >> + opensmtpd-configuration-cas >> + opensmtpd-configuration-interfaces >> + opensmtpd-configuration-socket >> + opensmtpd-configuration-includes >> + opensmtpd-configuration-matches >> + ;;opensmtpd-configuration-mda-wrappers >> + opensmtpd-configuration-mta-max-deferred >> + opensmtpd-configuration-srs >> + opensmtpd-configuration-smtp >> + opensmtpd-configuration-queue >> opensmtpd-service-type >> - %default-opensmtpd-config-file >> >> mail-aliases-service-type >> >> @@ -1641,22 +1784,2351 @@ (define (generate-dovecot-documentation) >> (listeners unix-listener-configuration fifo-listener- >> configuration >> inet-listener-configuration)) >> (protocol-configuration ,protocol-configuration-fields)) >> - 'dovecot-configuration)) >> + 'dovecot-configuration)) >> >> >> -;;; >> ;;; OpenSMTPD. >> ;;; >> +;;; This next bit of code helps me create my own sanitizer >> functions. >> + >> +;; some fieldnames have a default value of #f, which is ok. They >> cannot have >> +;; a value of #t. >> +;; for example opensmtpd-table-data can be #f, BUT NOT true. >> +;; my/sanitize procedure tests values to see if they are of the >> right kind. >> +;; procedure false? is needed to allow fields like 'values' to be >> blank, >> +;; (empty), or #f BUT also have a value like a list of strings. > Use less egocentric comments ;) I'm not sure what you mean here? I know I had a comment in my task list that said something like my sanitizer function are probably better than those found in guix. Apologies for that. > >> +(define (false? var) >> + (eq? #f var)) >> + >> +;; TODO I have to have this procedure, or I need to change >> my/sanitize >> +;; procedure. >> +(define (my-file-exists? file) >> + (and (string? file) >> + (access? file F_OK))) > Does file-exists? not work for you? The file-exists? function causes my-sanitize function to break. I think. If you get rid of it, then what happens when a user types in (file 4), you get an raise-exception. I can probably just rework my-sanitizer function to deal with that possibility, but I have not yet. I would love some guidance on how to do that. Because I feel like having to handle that exception is hard. > >> +;; This procedure takes in a var and a list of procedures. It loops >> through >> +;; list of procedures passing in var to each. >> +;; if one procedure returns #t, the function returns true. >> Otherwise #f. >> +;; TODO for fun rewrite this using map >> +;; If I rewrote it in map, then it may help with sanitizing. >> +;; eg: I could then potentially easily sanitize vars with lambda >> procedures. >> +(define (is-value-right-type? var list-of-procedures record >> fieldname) >> + (if (null? list-of-procedures) >> + #f >> + (if ((car list-of-procedures) var) >> + #t >> + (is-value-right-type? var (cdr list-of-procedures) record >> + fieldname)))) > Alternatively, (any (cut <> var) list-of-procedures). You mentioned that in the last review, I just can't figure out how to use your suggestion. This is the code that I have in the task list WIP: *** TODO simplify my sanitizing funcions (any (cut <> var)) #+BEGIN_SRC scheme (use-modules (ice-9 curried-definitions) (srfi srfi-26)) (define (((expect-any predicates) record field) var) (if (any (cut <> var) predicates) var (begin ;; code code code ;; how do I tell the user which function failed? (display "error") (throw 'bad! var)))) ;; here is how you use it. (name opensmtpd-table-name ;; string (default #f) (sanitize (lambda (var) (((expect-any (list string? number?)) "hello" "that") var)))) #+END_SRC Does that look close to what you want? I feel like it is way off, but I don't know. Honestly when I say this suggestion I was completely blown away, I have been using (any ) and (every) in a few places to get rid of some uses of primitive eval. > >> +;; converts strings like this: >> +;; "apple, ham, cherry" -> "apple, ham, or cherry" >> +;; "pineapple" -> "pinneapple". >> +;; "cheese, grapefruit, or jam" -> "cheese, grapefruit, or jam" >> +(define (add-comma-or string) >> + (define last-comma-location (string-rindex string #\,)) >> + (if last-comma-location >> + (if (string-contains string ", or" last-comma-location) >> + string >> + (string-replace string ", or" last-comma-location >> + (+ 1 last-comma-location))) >> + string)) >> + >> + >> +(define (list-of-procedures->string procedures) >> + (define string >> + (let loop ((procedures procedures)) >> + (if (null? procedures) >> + "" >> + (begin >> + (string-append >> + (cond ((eq? false? (car procedures)) >> + "#f, ") >> + ((eq? boolean? (car procedures)) >> + "a boolean, ") >> + ((eq? string? (car procedures)) >> + "a string, ") >> + ((eq? integer? (car procedures)) >> + "an integer, ") >> + ((eq? list-of-strings? (car procedures)) >> + "a list of strings, ") >> + ((eq? assoc-list? (car procedures)) >> + "an association list of strings, ") >> + ((eq? nested-list? (car procedures)) >> + "a nested-list of strings, ") >> + ((eq? opensmtpd-pki? (car procedures)) >> + "an <opensmtpd-pki> record, ") >> + ((eq? opensmtpd-table? (car procedures)) >> + "an <opensmtpd-table> record, ") >> + ((eq? list-of-opensmtpd-match? (car procedures)) >> + "a list of unique <opensmtpd-match> records, ") >> + ((eq? list-of-strings-or-gexps? (car procedures)) >> + "a list of strings or gexps, ") >> + ;; TODO can I remove the next two procedures? >> + ;; tables-data-are-a* ? I think I can. >> + ((eq? tables-data-are-assoc-list? (car >> procedures)) >> + (string-append >> + "an <opensmtpd-table> record whose fieldname >> 'data' are " >> + "an assoc-list.\nFor example: (opensmtpd-table >> " >> + "(name \"hostnames\") , " >> + "(data '((\"124.394.23.1\" . \"gnu.org\"))))")) >> + ((eq? tables-data-are-a-list-of-strings? >> + (car procedures)) >> + (string-append >> + "on <opensmtpd-table> record whose fieldname >> 'data' is " >> + "a list of strings.\n" >> + "For example: (opensmtpd-table (name >> \"domains\") , " >> + "(data (list \"gnu.org\" \"guix.gnu.org\")))")) >> + ((eq? my-file-exists? (car procedures)) >> + "a file, ") >> + (else "has an incorrect value, ")) >> + (loop (cdr procedures))))))) >> + (add-comma-or (string-append (string-drop-right string 2) ".\n"))) > (define (procedure->string) ...) > (define (procedures->string list) > (define strings (map procedure->string list)) > (string-append > (string-join (drop-right strings 1) ", ") > (if (> (length list) 1) ", or") > (last strings) > ".\n")) > >> +(define (list-of-strings-or-gexps? list) >> + (and (list? list) >> + (cond ((null? list) >> + #t) >> + ((or (string? (car list)) >> + (gexp? (car list)) >> + (local-file? (car list)) >> + (file-append? (car list)) >> + (plain-file? (car list)) >> + (computed-file? (car list)) >> + (program-file? (car list))) >> + (list-of-strings-or-gexps? (cdr list))) >> + (else #f)))) >> + >> +(define (my/sanitize var record fieldname list-of-procedures) >> + (define try-string >> + (string-append "Try " (list-of-procedures->string list-of- >> procedures))) >> + (if (is-value-right-type? var list-of-procedures record fieldname) >> + var >> + (begin >> + (cond ((string? var) >> + (report-error (G_ "(~a \"~a\") is invalid.~%") >> fieldname var)) >> + ((or (number? var) (boolean? var)) >> + (report-error (G_ "(~a ~a) is invalid.~%") fieldname >> var) ) >> + (else >> + (report-error (G_ "(~a ...) is invalid.~%Value is: >> ~a~%") >> + fieldname var))) >> + (display-hint (G_ try-string)) >> + (throw 'bad! var)))) > This procedure needs a proper name, like sanitize/check-type, but more > importantly, why not simply use define-configuration? Yes! I have slowly been realizing that I have been clumsily re-inventing define-configuration. I hope to switch to define-configuration, because a lot of this code would go away. But I need to explore how define-configuration works. That would be quite a major change. :) > > > Cheers
GNU bug tracking system
Copyright (C) 1999 Darren O. Benham,
1997,2003 nCipher Corporation Ltd,
1994-97 Ian Jackson.