From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: from mp11.migadu.com ([2001:41d0:8:6d80::]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits)) by ms5.migadu.com with LMTPS id aJUcOxqLq2NJFQAAbAwnHQ (envelope-from ) for ; Wed, 28 Dec 2022 01:17:31 +0100 Received: from aspmx1.migadu.com ([2001:41d0:8:6d80::]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits)) by mp11.migadu.com with LMTPS id uCImOxqLq2NSgQEA9RJhRA (envelope-from ) for ; Wed, 28 Dec 2022 01:17:30 +0100 Received: from lists.gnu.org (lists.gnu.org [209.51.188.17]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by aspmx1.migadu.com (Postfix) with ESMTPS id 45C5F187F3 for ; Wed, 28 Dec 2022 01:17:30 +0100 (CET) Received: from localhost ([::1] helo=lists1p.gnu.org) by lists.gnu.org with esmtp (Exim 4.90_1) (envelope-from ) id 1pAK80-0003Nd-7W; Tue, 27 Dec 2022 19:17:04 -0500 Received: from eggs.gnu.org ([2001:470:142:3::10]) by lists.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from ) id 1pAK7y-0003NB-Vu for guix-patches@gnu.org; Tue, 27 Dec 2022 19:17:03 -0500 Received: from debbugs.gnu.org ([209.51.188.43]) by eggs.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_128_GCM_SHA256:128) (Exim 4.90_1) (envelope-from ) id 1pAK7y-0006Tn-Ee for guix-patches@gnu.org; Tue, 27 Dec 2022 19:17:02 -0500 Received: from Debian-debbugs by debbugs.gnu.org with local (Exim 4.84_2) (envelope-from ) id 1pAK7x-0003jH-W5 for guix-patches@gnu.org; Tue, 27 Dec 2022 19:17:02 -0500 X-Loop: help-debbugs@gnu.org Subject: [bug#56046] [PATCH opensmtpd-records v3] services (opensmtpd): add opensmtpd records to enhance opensmtpd-configuration. Resent-From: Joshua Branson Original-Sender: "Debbugs-submit" Resent-CC: guix-patches@gnu.org Resent-Date: Wed, 28 Dec 2022 00:17:01 +0000 Resent-Message-ID: Resent-Sender: help-debbugs@gnu.org X-GNU-PR-Message: followup 56046 X-GNU-PR-Package: guix-patches X-GNU-PR-Keywords: patch To: Liliana Marie Prikler Cc: Joshua Branson , 56046@debbugs.gnu.org Received: via spool by 56046-submit@debbugs.gnu.org id=B56046.167218660214301 (code B ref 56046); Wed, 28 Dec 2022 00:17:01 +0000 Received: (at 56046) by debbugs.gnu.org; 28 Dec 2022 00:16:42 +0000 Received: from localhost ([127.0.0.1]:56774 helo=debbugs.gnu.org) by debbugs.gnu.org with esmtp (Exim 4.84_2) (envelope-from ) id 1pAK7b-0003iW-9g for submit@debbugs.gnu.org; Tue, 27 Dec 2022 19:16:42 -0500 Received: from mx1.dismail.de ([78.46.223.134]:22795) by debbugs.gnu.org with esmtp (Exim 4.84_2) (envelope-from ) id 1pAK7V-0003iB-VH for 56046@debbugs.gnu.org; Tue, 27 Dec 2022 19:16:38 -0500 Received: from mx1.dismail.de (localhost [127.0.0.1]) by mx1.dismail.de (OpenSMTPD) with ESMTP id 854a6e1a; Wed, 28 Dec 2022 01:16:26 +0100 (CET) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed; d=dismail.de; h=from:to:cc :subject:in-reply-to:references:date:message-id:mime-version :content-type:content-transfer-encoding; s=20190914; bh=7wtudcRk 9JQArJUw3ZCXpsFw8rPce1SXXcWJT0t0jPw=; b=LJV8hIYCzwN3KOfuBYxmz/zD 2Ym52RLsZiJHRiSuqViLDw1/L1rVLqP0NgDn4+Q4XfojT6fmMtjri5g0htWS47of 4NnFDwrmq+V6mBeG15gcx5ITqeiT9sQRQ3bAY4A59ORivGHFwn87r7V9SS/VKGEG h88rAs4AJopHoBShlIWGGxaAPbkCG3/OogZXhiwSXj5abGWZ2vdkiujPF9By6H8v aISXyr2+HsgaGt1PHcmgX/JY81xopB7O66sRbt3n4Aq8SYy/en7rykB2Eb3EZtXA 1P++C0zL2t3TVO+VdDSdphlPvxVO8BmOiNGD27n0ZlznyU1hyxvVxlWpIa557Q== Received: from smtp2.dismail.de ( [10.240.26.12]) by mx1.dismail.de (OpenSMTPD) with ESMTP id 0509335b; Wed, 28 Dec 2022 01:16:26 +0100 (CET) Received: from smtp2.dismail.de (localhost [127.0.0.1]) by smtp2.dismail.de (OpenSMTPD) with ESMTP id fe1e29eb; Wed, 28 Dec 2022 01:16:26 +0100 (CET) Received: by dismail.de (OpenSMTPD) with ESMTPSA id 21a917ca (TLSv1.3:TLS_AES_256_GCM_SHA384:256:NO); Wed, 28 Dec 2022 01:16:23 +0100 (CET) In-Reply-To: <37239abae388f1fadcba559b62c0aae07de9d319.camel@gmail.com> (Liliana Marie Prikler's message of "Mon, 26 Dec 2022 20:34:43 +0100") References: <8001f404c0e54baba71ef9c5536abc54275c4167.1671803496.git.joshua@gnucode.me> <37239abae388f1fadcba559b62c0aae07de9d319.camel@gmail.com> X-Gnus-Sucks: I know man Date: Tue, 27 Dec 2022 19:16:15 -0500 Message-ID: <87k02co01c.fsf@dismail.de> MIME-Version: 1.0 Content-Type: text/plain; charset=utf-8 Content-Transfer-Encoding: quoted-printable X-BeenThere: debbugs-submit@debbugs.gnu.org X-Mailman-Version: 2.1.18 Precedence: list X-BeenThere: guix-patches@gnu.org List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Reply-to: Joshua Branson X-ACL-Warn: , Joshua Branson via Guix-patches From: Joshua Branson via Guix-patches via Errors-To: guix-patches-bounces+larch=yhetil.org@gnu.org Sender: guix-patches-bounces+larch=yhetil.org@gnu.org X-Migadu-Country: US X-Migadu-Flow: FLOW_IN ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=yhetil.org; s=key1; t=1672186650; h=from:from:sender:sender:reply-to:reply-to:subject:subject:date:date: message-id:message-id:to:to:cc:cc:mime-version:mime-version: content-type:content-type: content-transfer-encoding:content-transfer-encoding:resent-cc: resent-from:resent-sender:resent-message-id:in-reply-to:in-reply-to: references:references:list-id:list-help:list-unsubscribe: list-subscribe:list-post:dkim-signature; bh=uefObM3ZDMAs6Pr7Fc9LmkD46RR2et2JS69IV/HbTIQ=; b=NAuANQEA62DrDajl0/oynZOyc3nhdK3Oneli96exyS2vOo7bpL6g4PuRAf6ht3lgKQw6u0 dyUJ1XK/+ijIDhzZzGNVtjg08/XaZaBITqldNix6jwFVdXh8rcDWXz51U7hJPL3HxcYFB6 SfA1HhVpHR2xp0GAVW4xqolVbdEbc8na9/zg4B9WlOWVE0B+qM+5mI5Up1xT1zO99mBl9O xESAeZWpMgj6+cH7/oXodYdGjqsypzip9luR3+gdJ4Ljz4sGaXtUsmvHpgtbzvKk0+TND3 dxxoDmINZ358AzEPbHaV5spB3WMzxTnv23SuopOa23XjBYbbkWE5XnOEk/x17w== ARC-Authentication-Results: i=1; aspmx1.migadu.com; dkim=fail ("headers rsa verify failed") header.d=dismail.de header.s=20190914 header.b=LJV8hIYC; spf=pass (aspmx1.migadu.com: domain of "guix-patches-bounces+larch=yhetil.org@gnu.org" designates 209.51.188.17 as permitted sender) smtp.mailfrom="guix-patches-bounces+larch=yhetil.org@gnu.org"; dmarc=pass (policy=none) header.from=gnu.org ARC-Seal: i=1; s=key1; d=yhetil.org; t=1672186650; a=rsa-sha256; cv=none; b=c2VisiYXqbZzvVCOb4caKggvdCWsHnaiSediDwXiiq6Z9V/G7gjGkiNE0VU+UQiZq1OlEm ZNDYrNQctwos/l3TX4qQtShlN70C3rqKPHFlfKgG1lQQUwMCk2FZxOnYfI0pwmdh9YmioL eC4fWSOG4lKYgKhKD7rQM7A6Iuatk/DLpW3XNPKwdum6dfYwF5/cT6auNKo0VmoW0KZxVw xIOfbXlV5W8VIIG74Qljz9keN3g4+sgvx2Rq3pykxdABUlrNreeEYRYt1YmiddALDQBcl8 1mmYjoXI4nAfutlkjsXvu1o8oB9ZiH33M7k/qg0y5jUpiw0kg4+BhWNyZNzaVw== X-Spam-Score: -2.13 X-Migadu-Queue-Id: 45C5F187F3 Authentication-Results: aspmx1.migadu.com; dkim=fail ("headers rsa verify failed") header.d=dismail.de header.s=20190914 header.b=LJV8hIYC; spf=pass (aspmx1.migadu.com: domain of "guix-patches-bounces+larch=yhetil.org@gnu.org" designates 209.51.188.17 as permitted sender) smtp.mailfrom="guix-patches-bounces+larch=yhetil.org@gnu.org"; dmarc=pass (policy=none) header.from=gnu.org X-Migadu-Scanner: scn1.migadu.com X-Migadu-Spam-Score: -2.13 X-TUID: UDj11QWEKaWx Liliana Marie Prikler writes: > Am Freitag, dem 23.12.2022 um 08:52 -0500 schrieb Joshua Branson: >>=20 >> * 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 e= mail 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. >>=20 >> * gnu/tests/mail.scm : new tests for various opensmtpd records. >>=20 >> * doc/guix.texi (OpenSMTPD Service): Added documentation for the >> new records for opensmtpd. >> --- >> =C2=A0doc/guix.texi=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 | 10= 65 ++++++++++++++++- >> =C2=A0gnu/services/mail.scm | 2560 >> ++++++++++++++++++++++++++++++++++++++++- >> =C2=A0gnu/tests/mail.scm=C2=A0=C2=A0=C2=A0 |=C2=A0 713 ++++++++++++ >> =C2=A03 files changed, 4310 insertions(+), 28 deletions(-) >>=20 >> 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: >> =C2=A0@end lisp >> =C2=A0 >> =C2=A0@subsubheading OpenSMTPD Service >> +@cindex opensmtpd >> =C2=A0 >> =C2=A0@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).=C2=A0 OpenSMTPD >> +@strong{listens} for incoming mail and @strong{matches} the mail to >> +@strong{actions}. The following records represent those stages: >> =C2=A0 >> -@lisp >> -(service opensmtpd-service-type >> -=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 (opensmtpd-configurati= on >> -=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 (config-fi= le (local-file "./my-smtpd.conf")))) >> +@multitable {aaaaaaaaa} >> {aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa} > I hope this will receive proper documentation. Users can still use (service opensmtpd-service-type =C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 (opensmtpd-configuration =C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 (config-file (= local-file "./my-smtpd.conf")))) config-file is still a fieldname of . Is that wha= t you mean? Also the generated documentation is available here: https://notabug.org/jbranso/linode-guix-system-configuration/src/master/ope= nsmtpd-records-documentation.txt >> +@item @strong{listens} >> +@tab @code{} >> +@item >> +@tab @code{} >> +@item >> +@tab >> +@item @strong{matches} >> +@tab @code{} >> +@item >> +@tab >> +@item @strong{actions} >> +@tab @code{} >> +@item >> +@tab @code{} >> +@end multitable >> + >> +Additionally, each @code{} and >> +@code{} may use a list of @code{> filter>}, >> +and/or @code{} records to filter >> +email/spam. Also numerous records' fieldnames use >> +@code{} records to hold lists or key value pairs of >> +data.=C2=A0 Be sure to read the @code{} section to lea= rn >> the >> +differance between a @code{mapping table} and a @code{list table}. >> + >> +Finally, both @code{} and >> +@code{} use @code{} to >> +configure various options. >> + >> +A simple example opensmtpd configuration is below: >> + >> +@lisp >> +(let ((smtp.gnu.org (opensmtpd-pki >> +=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2= =A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 (doma= in "smtp.gnu.org") >> +=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2= =A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 (cert= "file.cert") >> +=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2= =A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 (key = "file.key")))) >> +=C2=A0 (service opensmtpd-service-type >> +=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 (opensmtpd= -configuration >> +=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 (int= erfaces (list >> +=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2= =A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0= (opensmtpd-interface >> +=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2= =A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0= =C2=A0 (pki smtp.gnu.org)) >> +=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2= =A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0= (opensmtpd-interface >> +=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2= =A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0= =C2=A0 (pki smtp.gnu.org) >> +=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2= =A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0= =C2=A0 (secure-connection "smtps")))) >> +=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 (mat= ches (list >> +=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2= =A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 (opensmtpd-match >> +=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2= =A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 (action >> +=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2= =A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 (open= smtpd-local-delivery >> +=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2= =A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0= (name "local-delivery")))) >> +=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2= =A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 (opensmtpd-match >> +=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2= =A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 (action >> +=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2= =A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 (open= smtpd-relay >> +=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2= =A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0= (name "relay"))))))))) >> =C2=A0@end lisp >> =C2=A0@end deffn >> =C2=A0 >> @@ -25425,7 +25475,7 @@ Data type representing the configuration of >> opensmtpd. >> =C2=A0 >> =C2=A0@table @asis >> =C2=A0@item @code{package} (default: @var{opensmtpd}) >> -Package object of the OpenSMTPD SMTP server. >> +Package object of the OpenSMTPD server. >> =C2=A0 >> =C2=A0@item @code{config-file} (default: @code{%default-opensmtpd-config- >> file}) >> =C2=A0File-like object of the OpenSMTPD configuration file to use.=C2=A0= By >> default >> @@ -25433,14 +25483,1013 @@ it listens on the loopback network >> interface, and allows for mail from >> =C2=A0users and daemons on the local machine, as well as permitting email >> to >> =C2=A0remote servers.=C2=A0 Run @command{man smtpd.conf} for more inform= ation. >> =C2=A0 >> +@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 >> +=C2=A0 (opensmtpd-interface >> +=C2=A0=C2=A0=C2=A0 (interface "lo") >> +=C2=A0=C2=A0=C2=A0 (port 25))) >> +@end lisp >> +@code{interfaces} is a list of @code{} 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.=C2=A0 Run @code{man smtpd.conf} for more information. >> + >> +@item @code{matches} default: >> +@lisp >> +(list (opensmtpd-match >> +=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 (action (opensmtpd-local-delivery >> +=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2= =A0=C2=A0=C2=A0=C2=A0 (name "local") >> +=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2= =A0=C2=A0=C2=A0=C2=A0 (method "mbox") >> +=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2= =A0=C2=A0=C2=A0=C2=A0 (options >> +=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2= =A0=C2=A0=C2=A0=C2=A0=C2=A0 (list >> +=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2= =A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 (opensmtpd-option >> +=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2= =A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 (option "for local"))))))) >> +=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 (opensmtpd-match >> +=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 (action (opensmtpd-relay >> +=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2= =A0=C2=A0=C2=A0=C2=A0 (name "outbound"))) >> +=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 (options >> +=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 (list >> +=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 (opensmtpd-option >> +=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 (option "from lo= cal")) >> +=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 (opensmtpd-option >> +=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 (option "for any= ")))))) >> +@end lisp >> +@code{matches} is a list of @code{} 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{} 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{} 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{} record, which lets one >> set >> +up SRS, the Sender Rewritting Scheme. >> + >> =C2=A0@item @code{setgid-commands?} (default: @code{#t}) >> =C2=A0Make the following commands setgid to @code{smtpq} so they can be >> =C2=A0executed: @command{smtpctl}, @command{sendmail}, @command{send- >> mail}, >> =C2=A0@command{makemap}, @command{mailq}, and @command{newaliases}. >> =C2=A0@xref{Setuid Programs}, for more information on setgid programs. >> + >> =C2=A0@end table >> =C2=A0@end deftp >> =C2=A0 >> +@itemize >> +@item Data Type: opensmtpd-interface >> +Data type representing the configuration of an >> +@code{}. 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.=C2=A0 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.=C2=A0 Valid strings are >> +@code{"inet4"} or @code{"inet6"}, which will only listen on IPv4 or >> IPv6 >> +respectfully.=C2=A0 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.=C2=A0 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.=C2=A0 This allows the @code{} 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.=C2=A0 This option also accepts a @code{mappi= ng >> +table} that maps usernames to encrypted passwords. >> + >> +@item @code{filters} (default: @code{#f}) >> +A list of one or many @code{} or >> +@code{} 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 =E2=80=9CReceived= =E2=80=9D >> 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{} 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 =E2=80=9CReceived=E2=80=9D headers, report whethe= r 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}.=C2=A0 If >> +@code{#t}, then the From header is rewritten to match the sender >> +provided in the SMTP session.=C2=A0 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{}. 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{} or >> +@code{} 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 =E2=80=9CReceived= =E2=80=9D >> 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{} 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{} found in fieldname >> +@code{action}.=C2=A0 Here is an example @code{opensmtpd-match} >> +record. >> + >> +@lisp >> +(opensmtpd-match >> + (action (opensmtpd-local-delivery >> +=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 (name "receive") >> +=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 (method (opensmt= pd-maildir >> +=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2= =A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 (pathname "/home/%@{rcpt.user@}/Mai= ldir") >> +=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2= =A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 (junk #t))) >> +=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 (virtual (opensm= tpd-table >> +=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2= =A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 (name "virt") >> +=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2= =A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 (data '(("carmen" . "carmen@@= gnu.org"))))))) >> + (options (list (opensmtpd-option >> +=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2= =A0=C2=A0=C2=A0=C2=A0=C2=A0 (option "from any")) >> +=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2= =A0=C2=A0=C2=A0=C2=A0 (opensmtpd-option >> +=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2= =A0=C2=A0=C2=A0=C2=A0=C2=A0 (option "for domain") >> +=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2= =A0=C2=A0=C2=A0=C2=A0=C2=A0 (data (opensmtpd-table >> +=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2= =A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 (name= "domain-table") >> +=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2= =A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 (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{} or >> +@code{}. >> + >> +@item @code{options} (default: @code{#f}) >> +The fieldname @code{option} is a list of unique >> +@code{} 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 is it documented like this: =E2=80=A2 Data Type: opensmtpd-option This data type represents the configuration of an =E2=80=98=E2=80=99, which is used by =E2=80=98=E2=80=99 and =E2=80=98= =E2=80=99 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 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{}'s fieldname @code{data}.=C2=A0 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 >> +=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 (opensmtpd-option >> +=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 (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 >> +=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 (opensmtpd-option >> +=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 (option "tag") >> +=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 (data "this-tag")) >> +@end lisp >> + >> +@item @code{"for rcpt"} _domain_ | >> +This option requires fieldname @code{data} to have a string domain >> or >> +@code{list table}: >> + >> +@lisp >> +=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 (opensmtpd-option >> +=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 (option "for rcpt") >> +=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 (data "gnu.org")) >> +@end lisp >> + >> +OR >> + >> +@lisp >> +=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 (opensmtpd-option >> +=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 (option "for rcpt") >> +=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 (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: ), 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.=C2=A0 This is the >> default, >> +and may be omitted. >> + >> +@item @code{"for domain"} _domain_ | >> +Specify that session may address the string _domain_ or >> +@code{list table} . >> + >> +@item @code{"for rcpt-to"} _recipient_ | >> +Specify that session may address the string _recipient_ or list >> table >> +. >> + >> +@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_ | >> +Specify that the session may originate from authenticated _user_ or >> +@code{list table} , 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.=C2=A0 This is the default, and may be omitted. >> + >> +@item @code{"from mail-from"} _sender_ | >> +Specify that session may originate from _sender_ or @code{list >> table} >> +, 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_ | >> +Specify that session may only originate from an IP address that >> resolves >> +to a reverse DNS matching string _hostname_ or @code{list table} >> +. >> + >> +@item @samp{"from socket"} >> +Specify that session may only originate from the local enqueuer. >> + >> +@item @code{"from src"} _address_ |
>> +Specify that session may only originate from string _address_ or >> +@code{list table}
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_ | >> +Matches transactions which have been authenticated for string _user_ >> or >> +@code{list table} . >> + >> +@item @code{"helo"} _helo-name_ | >> +Specify that session's HELO / EHLO should match the string _helo- >> name_ >> +or @code{list table} . >> + >> +@item @code{"mail-from"} _sender_ | >> +Specify that transactions's MAIL FROM should match the string >> _sender_ >> +or @code{list table} . >> + >> +@item @code{"rcpt-to"} _recipient_ | >> +Specify that transaction's RCPT TO should match the string >> _recipient_ >> +or @code{list table} . >> + >> +@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{} 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.=C2=A0 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{} >> +Deliver the message to an LMTP server at @code{}'s >> +fieldname @code{destination}. The location may be expressed as >> string >> +host:port or as a UNIX socket. Optionally, @code{}'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{} >> +Deliver the message to the maildir in >> +@code{}'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{}'s record fieldname @code{junk} is >> @code{#t}, >> +then message will be moved to the =E2=80=98Junk=E2=80=99 folder if it c= ontains a >> positive >> +=E2=80=98X-Spam=E2=80=99 header. This folder will be created under fiel= dname >> @code{pathname} if >> +it does not yet exist. >> + >> +@item @code{} >> +Delegate the delivery to the @code{}'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.=C2=A0 It's >> +format is @code{n@{s|m|h|d@}}.=C2=A0 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{} 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{} record is used for >> virtual >> +expansion. >> +@end itemize >> + >> +@item Data Type: opensmtpd-relay >> +This data type represents the configuration of an >> +@code{} 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{} 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{} 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. I= f 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.=C2=A0 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{} (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{} >> +Use the alist @code{} 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{> table>} >> +Use the string or @code{} 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{}. 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.=C2=A0 If @code{proc-exec} is >> @code{#t}, @code{proc} is >> +treated as a command to execute.=C2=A0 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{}. >> + >> +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{} 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{} records. >> + >> +At each phase, various options, specified by a list of >> +@code{}, may be checked. The >> +@code{}'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{
} next to them require >> the >> +@code{}'s fieldname @code{data} to be an >> +@code{}. 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"}
>> +@tab session has a reverse DNS in table >> +@item @code{"src"}
>> +@tab source address is in table >> +@item @code{"helo"}
>> +@tab helo name is in table >> +@item @code{"auth"} >> +@tab session is authenticated >> +@item @code{"auth"}
>> +@tab session username is in table >> +@item @code{"mail-from"}
>> +@tab sender address is in table >> +@item @code{"rcpt-to"}
>> +@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}.=C2=A0 The value and message may be put in the >> +@code{}'s fieldname @code{data}.=C2=A0 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=C2=A0 i.e., an =E2=80=98X-Spam: yes=E2=80=99 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.=C2=A0 @code{value} and @code{message} are mutually >> exclusive. >> +@end itemize >> + >> +@item Data Type: opensmtpd-option >> +This data type represents the configuration of an >> +@code{}, which is used by >> +@code{} and @code{} >> +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{}. When >> the >> +option record is used inside of an @code{}, >> 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{} is used inside of an >> +@code{}, 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{> table>} >> +Some options require a string or @code{} 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{}. >> + >> +@itemize >> +@item @code{name} (default @code{#f}) >> +@code{name} is the name of the @code{} 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") >> +=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 ("jennifer" . "$encryptedPas= sword2))) >> +@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") >> +=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 ("user2" "james@@guix.gnu.or= g" "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{}. >> + >> +@itemize >> +@item @code{domain} (default @code{#f}) >> +@code{domain} is the string name of the @code{} >> 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{=E2=80=98Junk=E2=80=99} >> +folder if it contains a positive @samp{=E2=80=98X-Spam=E2=80=99} 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@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 (=E2=80=98-= =E2=80=99) 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{} record. >> + >> +@itemize >> +@item @code{ciphers} (default: @code{#f}) >> +Set the control string for >> SSL@math{_CTX}@math{_set}@math{_cipher}@math{_list}(3).=C2=A0 The default >> is >> +=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 ``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@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{}, @code{}) 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.=C2=A0 For example, with recipient domain >> @samp{=E2=80=9Cexample.org=E2=80=9D}: >> + >> +@multitable {aaaaaaaaaaaaaaaaaaaaaa} {aaaaaaaaaaaaaaaaaaaa} >> +@item @samp{%@{rcpt.domain[0]@}} >> +@tab expands to =E2=80=9Ce=E2=80=9D >> +@item @samp{%@{rcpt.domain[1]@}} >> +@tab expands to =E2=80=9Cx=E2=80=9D >> +@item @samp{%@{rcpt.domain[8:]@}} >> +@tab expands to =E2=80=9Corg=E2=80=9D >> +@item @samp{%@{rcpt.domain[-3:]@}} >> +@tab expands to =E2=80=9Corg=E2=80=9D >> +@item @samp{%@{rcpt.domain[0:6]@}} >> +@tab expands to =E2=80=9Cexample=E2=80=9D >> +@item @samp{%@{rcpt.domain[0:-4]@}} >> +@tab expands to =E2=80=9Cexample=E2=80=9D >> +@end multitable >> + >> +In addition, modifiers may be applied to the token.=C2=A0 For example, >> with recipient >> +@samp{=E2=80=9CUser+Tag@@Example.org=E2=80=9D}: >> + >> +@multitable {aaaaaaaaaaaaaaaaaaaaaaaa} >> {aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa} >> +@item @samp{%@{rcpt:lowercase@}} >> +@tab expands to =E2=80=9Cuser+tag@@example.org=E2=80=9D >> +@item @samp{%@{rcpt:uppercase@}} >> +@tab expands to =E2=80=9CUSER+TAG@@EXAMPLE.ORG=E2=80=9D >> +@item @samp{%@{rcpt:strip@}} >> +@tab expands to =E2=80=9CUser@@Example.org=E2=80=9D >> +@item @samp{%@{rcpt:lowercasestrip@}} >> +@tab expands to =E2=80=9Cuser@@example.org=E2=80=9D >> +@end multitable >> + >> +For security concerns, expanded values are sanitized and potentially >> dangerous >> +characters are replaced with =E2=80=98:=E2=80=99. In situations where t= hey are >> desirable, the >> +=E2=80=9Craw=E2=80=9D modifier may be applied. For example, with recipi= ent >> +@samp{=E2=80=9Cuser+t?g@@example.org=E2=80=9D}: >> + >> +@multitable {aaaaaaaaaaaaa} {aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa} >> +@item @samp{%@{rcpt@}} >> +@tab expands to =E2=80=9Cuser+t:g@@example.org=E2=80=9D >> +@item @samp{%@{rcpt:raw@}} >> +@tab expands to =E2=80=9Cuser+t?g@@example.org=E2=80=9D >> +@end multitable >> +@end itemize >> + >> =C2=A0@subsubheading Exim Service >> =C2=A0 >> =C2=A0@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) >> =C2=A0=C2=A0 #:use-module (gnu packages admin) >> =C2=A0=C2=A0 #:use-module (gnu packages dav) >> =C2=A0=C2=A0 #:use-module (gnu packages tls) >> +=C2=A0 #:use-module (guix i18n) >> +=C2=A0 #:use-module (guix diagnostics) >> +=C2=A0 #:use-module (guix ui) >> +=C2=A0 #:use-module (guix utils) >> =C2=A0=C2=A0 #:use-module (guix records) >> =C2=A0=C2=A0 #:use-module (guix packages) >> =C2=A0=C2=A0 #:use-module (guix gexp) >> @@ -58,10 +62,149 @@ (define-module (gnu services mail) >> =C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0= mailbox-configuration >> =C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0= namespace-configuration >> =C2=A0 >> +=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 open= smtpd-table >> +=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 open= smtpd-table? >> +=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 open= smtpd-table-name >> +=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 open= smtpd-table-data >> + >> +=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 open= smtpd-ca >> +=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 open= smtpd-ca? >> +=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 open= smtpd-ca-name >> +=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 open= smtpd-ca-file >> + >> +=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 open= smtpd-pki >> +=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 open= smtpd-pki? >> +=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 open= smtpd-pki-domain >> +=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 open= smtpd-pki-cert >> +=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 open= smtpd-pki-key >> +=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 open= smtpd-pki-dhe >> + >> +=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 open= smtpd-local-delivery >> +=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 open= smtpd-local-delivery? >> +=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 open= smtpd-local-delivery-method >> +=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 open= smtpd-local-delivery-alias >> +=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 open= smtpd-local-delivery-ttl >> +=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 open= smtpd-local-delivery-user >> +=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 open= smtpd-local-delivery-userbase >> +=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 open= smtpd-local-delivery-virtual >> +=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 open= smtpd-local-delivery-wrapper >> + >> +=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 open= smtpd-maildir >> +=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 open= smtpd-maildir? >> +=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 open= smtpd-maildir-pathname >> +=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 open= smtpd-maildir-junk >> + >> +=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 open= smtpd-mda >> +=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 open= smtpd-mda-name >> +=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 open= smtpd-mda-command >> + >> +=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 open= smtpd-lmtp >> +=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 open= smtpd-lmtp-destination >> +=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 open= smtpd-lmtp-rcpt >> + >> +=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 open= smtpd-relay >> +=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 open= smtpd-relay? >> +=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 open= smtpd-relay-name >> +=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 open= smtpd-relay-backup >> +=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 open= smtpd-relay-backup-mx >> +=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 open= smtpd-relay-helo >> +=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 open= smtpd-relay-domain >> +=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 open= smtpd-relay-host >> +=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 open= smtpd-relay-pki >> +=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 open= smtpd-relay-srs >> +=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 open= smtpd-relay-tls >> +=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 open= smtpd-relay-auth >> +=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 open= smtpd-relay-mail-from >> +=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 open= smtpd-relay-src >> + >> +=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 open= smtpd-option >> +=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 open= smtpd-option? >> +=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 open= smtpd-option-option >> +=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 open= smtpd-option-bool >> +=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 open= smtpd-option-regex >> +=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 open= smtpd-option-data >> + >> +=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 open= smtpd-filter-phase >> +=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 open= smtpd-filter-phase? >> +=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 open= smtpd-filter-phase-name >> +=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 open= smtpd-filter-phase-phase >> +=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 open= smtpd-filter-phase-options >> +=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 open= smtpd-filter-phase-decision >> +=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 open= smtpd-filter-phase-message >> +=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 open= smtpd-filter-phase-value >> + >> +=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 open= smtpd-filter >> +=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 open= smtpd-filter? >> +=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 open= smtpd-filter-name >> +=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 open= smtpd-filter-proc >> + >> +=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 open= smtpd-interface >> +=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 open= smtpd-interface? >> +=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 open= smtpd-interface-interface >> +=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 open= smtpd-interface-family >> +=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 open= smtpd-interface-auth >> +=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 open= smtpd-interface-auth-optional >> +=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 open= smtpd-interface-filters >> +=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 open= smtpd-interface-hostname >> +=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 open= smtpd-interface-hostnames >> +=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 open= smtpd-interface-mask-src >> +=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 open= smtpd-interface-disable-dsn >> +=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 open= smtpd-interface-pki >> +=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 open= smtpd-interface-port >> +=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 open= smtpd-interface-proxy-v2 >> +=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 open= smtpd-interface-received-auth >> +=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 open= smtpd-interface-senders >> +=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 open= smtpd-interface-masquerade >> +=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 open= smtpd-interface-secure-connection >> +=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 open= smtpd-interface-tag >> + >> +=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 open= smtpd-socket >> +=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 open= smtpd-socket? >> +=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 open= smtpd-socket-filters >> +=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 open= smtpd-socket-mask-src >> +=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 open= smtpd-socket-tag >> + >> +=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 open= smtpd-match >> +=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 open= smtpd-match? >> +=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 open= smtpd-match-action >> +=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 open= smtpd-match-options >> + >> +=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 open= smtpd-smtp >> +=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 open= smtpd-smtp? >> +=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 open= smtpd-smtp-ciphers >> +=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 open= smtpd-smtp-limit-max-mails >> +=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 open= smtpd-smtp-limit-max-rcpt >> +=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 open= smtpd-smtp-max-message-size >> +=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 open= smtpd-smtp-sub-addr-delim character >> + >> +=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 open= smtpd-srs >> +=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 open= smtpd-srs? >> +=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 open= smtpd-srs-key >> +=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 open= smtpd-srs-backup-key >> +=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 open= smtpd-srs-ttl-delay >> + >> +=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 open= smtpd-queue >> +=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 open= smtpd-queue? >> +=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 open= smtpd-queue-compression >> +=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 open= smtpd-queue-encryption >> +=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 open= smtpd-queue-ttl-delay >> + >> =C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0= opensmtpd-configuration >> =C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0= opensmtpd-configuration? >> +=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 open= smtpd-package >> +=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 open= smtpd-config-file >> +=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 open= smtpd-configuration-bounce >> +=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 open= smtpd-configuration-cas >> +=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 open= smtpd-configuration-interfaces >> +=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 open= smtpd-configuration-socket >> +=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 open= smtpd-configuration-includes >> +=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 open= smtpd-configuration-matches >> +=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 ;;op= ensmtpd-configuration-mda-wrappers >> +=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 open= smtpd-configuration-mta-max-deferred >> +=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 open= smtpd-configuration-srs >> +=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 open= smtpd-configuration-smtp >> +=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 open= smtpd-configuration-queue >> =C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0= opensmtpd-service-type >> -=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 %def= ault-opensmtpd-config-file >> =C2=A0 >> =C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0= mail-aliases-service-type >> =C2=A0 >> @@ -1641,22 +1784,2351 @@ (define (generate-dovecot-documentation) >> =C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 (listeners unix-listener-conf= iguration fifo-listener- >> configuration >> =C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0= =C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 inet-listener-configuration)) >> =C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 (protocol-configuration ,protocol-c= onfiguration-fields)) >> -=C2=A0 'dovecot-configuration)) >> +=C2=A0=C2=A0 'dovecot-configuration)) >> =C2=A0 >> =C2=A0 >> -;;; >> =C2=A0;;; OpenSMTPD. >> =C2=A0;;; >> +;;; This next bit of code helps me create my own sanitizer >> functions. >> + >> +;; some fieldnames have a default value of #f, which is ok.=C2=A0 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 fo= und in guix. Apologies for that. > >> +(define (false? var) >> +=C2=A0 (eq? #f var)) >> + >> +;; TODO I have to have this procedure, or I need to change >> my/sanitize >> +;; procedure. >> +(define (my-file-exists? file) >> +=C2=A0 (and (string? file) >> +=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 (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 w= ith 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.=C2=A0 It loo= ps >> through >> +;; list of procedures passing in var to each. >> +;; if one procedure returns #t, the function returns true.=C2=A0 >> 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) >> +=C2=A0 (if (null? list-of-procedures) >> +=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 #f >> +=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 (if ((car list-of-procedures) var) >> +=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 #t >> +=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 (is-value-right-= type? var (cdr list-of-procedures) record >> +=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2= =A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0= =C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 fieldname)))) > Alternatively, (any (cut <> var) list-of-procedures). You mentioned that in the last review, I just can't figure out how to use y= our 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") v= ar)))) #+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 ha= ve 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) >> +=C2=A0 (define last-comma-location (string-rindex string #\,)) >> +=C2=A0 (if last-comma-location >> +=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 (if (string-contains string ", or" last-= comma-location) >> +=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 string >> +=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 (string-replace = string ", or" last-comma-location >> +=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2= =A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0= =C2=A0 (+ 1 last-comma-location))) >> +=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 string)) >> + >> + >> +(define (list-of-procedures->string procedures) >> +=C2=A0 (define string >> +=C2=A0=C2=A0=C2=A0 (let loop ((procedures procedures)) >> +=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 (if (null? procedures) >> +=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 "" >> +=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 (begin >> +=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 (str= ing-append >> +=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2= =A0 (cond ((eq? false? (car procedures)) >> +=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2= =A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 "#f, ") >> +=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2= =A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 ((eq? boolean? (car procedures)) >> +=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2= =A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 "a boolean, ") >> +=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2= =A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 ((eq? string? (car procedures)) >> +=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2= =A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 "a string, ") >> +=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2= =A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 ((eq? integer? (car procedures)) >> +=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2= =A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 "an integer, ") >> +=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2= =A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 ((eq? list-of-strings? (car procedu= res)) >> +=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2= =A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 "a list of strings, ") >> +=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2= =A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 ((eq? assoc-list? (car procedures)) >> +=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2= =A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 "an association list of strin= gs, ") >> +=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2= =A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 ((eq? nested-list? (car procedures)) >> +=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2= =A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 "a nested-list of strings, ") >> +=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2= =A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 ((eq? opensmtpd-pki? (car procedure= s)) >> +=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2= =A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 "an record, ") >> +=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2= =A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 ((eq? opensmtpd-table? (car procedu= res)) >> +=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2= =A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 "an record,= ") >> +=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2= =A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 ((eq? list-of-opensmtpd-match? (car= procedures)) >> +=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2= =A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 "a list of unique records, ") >> +=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2= =A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 ((eq? list-of-strings-or-gexps? (ca= r procedures)) >> +=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2= =A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 "a list of strings or gexps, = ") >> +=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2= =A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 ;; TODO can I remove the next two p= rocedures? >> +=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2= =A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 ;; tables-data-are-a* ?=C2=A0 I thi= nk I can. >> +=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2= =A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 ((eq? tables-data-are-assoc-list? (= car >> procedures)) >> +=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2= =A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 (string-append >> +=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2= =A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 "an r= ecord whose fieldname >> 'data' are " >> +=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2= =A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 "an assoc-list.\nFor ex= ample: (opensmtpd-table=C2=A0 >> " >> +=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2= =A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 "(name \"hostnames\") ,= " >> +=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2= =A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 "(data '((\"124.394.23.= 1\" . \"gnu.org\"))))")) >> +=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2= =A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 ((eq? tables-data-are-a-list-of-str= ings? >> +=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2= =A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0= (car procedures)) >> +=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2= =A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 (string-append >> +=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2= =A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 "on r= ecord whose fieldname >> 'data' is " >> +=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2= =A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 "a list of strings.\n" >> +=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2= =A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 "For example: (opensmtp= d-table (name >> \"domains\") , " >> +=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2= =A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 "(data (list \"gnu.org\= " \"guix.gnu.org\")))")) >> +=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2= =A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 ((eq? my-file-exists? (car procedur= es)) >> +=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2= =A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 "a file, ") >> +=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2= =A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 (else "has an incorrect value, ")) >> +=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2= =A0 (loop (cdr procedures))))))) >> +=C2=A0 (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) >> +=C2=A0 (and (list? list) >> +=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 (cond ((null? list) >> +=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2= =A0=C2=A0 #t) >> +=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2= =A0 ((or (string? (car list)) >> +=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2= =A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 (gexp? (car list)) >> +=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2= =A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 (local-file? (car list)) >> +=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2= =A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 (file-append? (car list)) >> +=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2= =A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 (plain-file? (car list)) >> +=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2= =A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 (computed-file? (car list)) >> +=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2= =A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 (program-file? (car list))) >> +=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2= =A0=C2=A0 (list-of-strings-or-gexps? (cdr list))) >> +=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2= =A0 (else #f)))) >> + >> +(define (my/sanitize var record fieldname list-of-procedures) >> +=C2=A0 (define try-string >> +=C2=A0=C2=A0=C2=A0 (string-append "Try " (list-of-procedures->string li= st-of- >> procedures))) >> +=C2=A0 (if (is-value-right-type? var list-of-procedures record fieldnam= e) >> +=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 var >> +=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 (begin >> +=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 (cond ((string? var) >> +=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2= =A0=C2=A0=C2=A0 (report-error (G_ "(~a \"~a\") is invalid.~%") >> fieldname var)) >> +=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2= =A0=C2=A0 ((or (number? var) (boolean? var)) >> +=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2= =A0=C2=A0 (report-error (G_ "(~a ~a) is invalid.~%") fieldname >> var) ) >> +=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2= =A0=C2=A0 (else >> +=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2= =A0=C2=A0=C2=A0 (report-error (G_ "(~a ...) is invalid.~%Value is: >> ~a~%") >> +=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2= =A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0= =C2=A0=C2=A0=C2=A0=C2=A0 fieldname var))) >> +=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 (display-hint (G_ try-string= )) >> +=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 (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 l= ot of this code would go away. But I need to explore how define-configuration wor= ks. That would be quite a major change. :) > > > Cheers