summaryrefslogtreecommitdiffstats
path: root/README_FILES/SMTPD_POLICY_README
diff options
context:
space:
mode:
Diffstat (limited to 'README_FILES/SMTPD_POLICY_README')
-rw-r--r--README_FILES/SMTPD_POLICY_README651
1 files changed, 651 insertions, 0 deletions
diff --git a/README_FILES/SMTPD_POLICY_README b/README_FILES/SMTPD_POLICY_README
new file mode 100644
index 0000000..47a6fa3
--- /dev/null
+++ b/README_FILES/SMTPD_POLICY_README
@@ -0,0 +1,651 @@
+PPoossttffiixx SSMMTTPP AAcccceessss PPoolliiccyy DDeelleeggaattiioonn
+
+-------------------------------------------------------------------------------
+
+PPuurrppoossee ooff PPoossttffiixx SSMMTTPP aacccceessss ppoolliiccyy ddeelleeggaattiioonn
+
+The Postfix SMTP server has a number of built-in mechanisms to block or accept
+mail at specific SMTP protocol stages. In addition, the Postfix SMTP server can
+delegate decisions to an external policy server (Postfix 2.1 and later).
+
+With this policy delegation mechanism, a simple greylist policy can be
+implemented with only a dozen lines of Perl, as is shown at the end of this
+document. A complete example can be found in the Postfix source code, in the
+directory examples/smtpd-policy.
+
+Another example of policy delegation is the SPF policy server at https://
+web.archive.org/web/20190221142057/http://www.openspf.org/Software.
+
+Policy delegation is now the preferred method for adding policies to Postfix.
+It's much easier to develop a new feature in few lines of Perl, Python, Ruby,
+or TCL, than trying to do the same in C code. The difference in performance
+will be unnoticeable except in the most demanding environments. On active
+systems a policy daemon process is used multiple times, for up to $max_use
+incoming SMTP connections.
+
+This document covers the following topics:
+
+ * Policy protocol description
+ * Simple policy client/server configuration
+ * Advanced policy client configuration
+ * Example: greylist policy server
+ * Greylisting mail from frequently forged domains
+ * Greylisting all your mail
+ * Routine greylist maintenance
+ * Example Perl greylist server
+
+PPrroottooccooll ddeessccrriippttiioonn
+
+The Postfix policy delegation protocol is really simple. The client sends a
+request and the server sends a response. Unless there was an error, the server
+must not close the connection, so that the same connection can be used multiple
+times.
+
+The client request is a sequence of name=value attributes separated by newline,
+and is terminated by an empty line. The server reply is one name=value
+attribute and it, too, is terminated by an empty line.
+
+Here is an example of all the attributes that the Postfix SMTP server sends in
+a delegated SMTPD access policy request:
+
+ PPoossttffiixx vveerrssiioonn 22..11 aanndd llaatteerr::
+ request=smtpd_access_policy
+ protocol_state=RCPT
+ protocol_name=SMTP
+ helo_name=some.domain.tld
+ queue_id=8045F2AB23
+ sender=foo@bar.tld
+ recipient=bar@foo.tld
+ recipient_count=0
+ client_address=1.2.3.4
+ client_name=another.domain.tld
+ reverse_client_name=another.domain.tld
+ instance=123.456.7
+ PPoossttffiixx vveerrssiioonn 22..22 aanndd llaatteerr::
+ sasl_method=plain
+ sasl_username=you
+ sasl_sender=
+ size=12345
+ ccert_subject=solaris9.porcupine.org
+ ccert_issuer=Wietse+20Venema
+ ccert_fingerprint=C2:9D:F4:87:71:73:73:D9:18:E7:C2:F3:C1:DA:6E:04
+ PPoossttffiixx vveerrssiioonn 22..33 aanndd llaatteerr::
+ encryption_protocol=TLSv1/SSLv3
+ encryption_cipher=DHE-RSA-AES256-SHA
+ encryption_keysize=256
+ etrn_domain=
+ PPoossttffiixx vveerrssiioonn 22..55 aanndd llaatteerr::
+ stress=
+ PPoossttffiixx vveerrssiioonn 22..99 aanndd llaatteerr::
+ ccert_pubkey_fingerprint=68:B3:29:DA:98:93:E3:40:99:C7:D8:AD:5C:B9:C9:40
+ PPoossttffiixx vveerrssiioonn 33..00 aanndd llaatteerr::
+ client_port=1234
+ PPoossttffiixx vveerrssiioonn 33..11 aanndd llaatteerr::
+ policy_context=submission
+ PPoossttffiixx vveerrssiioonn 33..22 aanndd llaatteerr::
+ server_address=10.3.2.1
+ server_port=54321
+ PPoossttffiixx vveerrssiioonn 33..88 aanndd llaatteerr::
+ compatibility_level=major.minor.patch
+ mail_version=3.8.0
+ [empty line]
+
+Notes:
+
+ * The "request" attribute is required. In this example the request type is
+ "smtpd_access_policy".
+
+ * The order of the attributes does not matter. The policy server should
+ ignore any attributes that it does not care about.
+
+ * When the same attribute name is sent more than once, the server may keep
+ the first value or the last attribute value.
+
+ * When an attribute value is unavailable, the client either does not send the
+ attribute, sends the attribute with an empty value ("name="), or sends a
+ zero value ("name=0") in the case of a numerical attribute.
+
+ * The "recipient" attribute is available in the "RCPT TO" stage. It is also
+ available in the "DATA" and "END-OF-MESSAGE" stages if Postfix accepted
+ only one recipient for the current message. The DATA protocol state also
+ applies to email that is received with BDAT commands (Postfix 3.4 and
+ later).
+
+ * The "recipient_count" attribute (Postfix 2.3 and later) is non-zero only in
+ the "DATA" and "END-OF-MESSAGE" stages. It specifies the number of
+ recipients that Postfix accepted for the current message. The DATA protocol
+ state also applies to email that is received with BDAT commands (Postfix
+ 3.4 and later).
+
+ * The remote client or local server IP address is an IPv4 dotted quad in the
+ form 1.2.3.4 or it is an IPv6 address in the form 1:2:3::4:5:6.
+
+ * The remote client or local server port is a decimal number in the range 0-
+ 65535.
+
+ * For a discussion of the differences between reverse and verified
+ client_name information, see the reject_unknown_client_hostname discussion
+ in the postconf(5) document.
+
+ * An attribute name must not contain "=", null or newline, and an attribute
+ value must not contain null or newline.
+
+ * The "instance" attribute value can be used to correlate different requests
+ regarding the same message delivery. These requests are sent over the same
+ policy connection (unless the policy daemon terminates the connection).
+ Once Postfix sends a query with a different instance attribute over that
+ same policy connection, the previous message delivery is either completed
+ or aborted.
+
+ * The "size" attribute value specifies the message size that the client
+ specified in the MAIL FROM command (zero if none was specified). With
+ Postfix 2.2 and later, it specifies the actual message size after the
+ client sends the END-OF-MESSAGE.
+
+ * The "sasl_*" attributes (Postfix 2.2 and later) specify information about
+ how the client was authenticated via SASL. These attributes are empty in
+ case of no SASL authentication.
+
+ * The "ccert_*" attributes (Postfix 2.2 and later) specify information about
+ how the client was authenticated via TLS. These attributes are empty in
+ case of no certificate authentication. As of Postfix 2.2.11 these attribute
+ values are encoded as xtext: some characters are represented by +XX, where
+ XX is the two-digit hexadecimal representation of the character value. With
+ Postfix 2.6 and later, the decoded string is an UTF-8 string without non-
+ printable ASCII characters.
+
+ * The "encryption_*" attributes (Postfix 2.3 and later) specify information
+ about how the connection is encrypted. With plaintext connections the
+ protocol and cipher attributes are empty and the keysize is zero.
+
+ * The "etrn_domain" attribute is defined only in the context of the ETRN
+ command, and specifies the ETRN command parameter.
+
+ * The "stress" attribute is either empty or "yes". See the STRESS_README
+ document for further information.
+
+ * The "policy_context" attribute provides a way to pass information that is
+ not available via other attributes (Postfix version 3.1 and later).
+
+ * The "compatibility_level" attribute corresponds to the compatibility_level
+ parameter value. It has the form major.minor.patch where minor and patch
+ may be absent.
+
+ * The "mail_version" attribute corresponds to the mail_version parameter
+ value. It has the form major.minor.patch for stable releases, and
+ major.minor-yyyymmdd for unstable releases.
+
+The following is specific to SMTPD delegated policy requests:
+
+ * Protocol names are ESMTP or SMTP.
+
+ * Protocol states are CONNECT, EHLO, HELO, MAIL, RCPT, DATA, END-OF-MESSAGE,
+ VRFY or ETRN; these are the SMTP protocol states where the Postfix SMTP
+ server makes an OK/REJECT/HOLD/etc. decision. The DATA protocol state also
+ applies to email that is received with BDAT commands (Postfix 3.4 and
+ later).
+
+The policy server replies with any action that is allowed in a Postfix SMTPD
+access(5) table. Example:
+
+ action=defer_if_permit Service temporarily unavailable
+ [empty line]
+
+This causes the Postfix SMTP server to reject the request with a 450 temporary
+error code and with text "Service temporarily unavailable", if the Postfix SMTP
+server finds no reason to reject the request permanently.
+
+In case of trouble the policy server must not send a reply. Instead the server
+must log a warning and disconnect. Postfix will retry the request at some later
+time.
+
+SSiimmppllee ppoolliiccyy cclliieenntt//sseerrvveerr ccoonnffiigguurraattiioonn
+
+The Postfix delegated policy client can connect to a TCP socket or to a UNIX-
+domain socket. Examples:
+
+ inet:127.0.0.1:9998
+ unix:/some/where/policy
+ unix:private/policy
+
+The first example specifies that the policy server listens on a TCP socket at
+127.0.0.1 port 9998. The second example specifies an absolute pathname of a
+UNIX-domain socket. The third example specifies a pathname relative to the
+Postfix queue directory; use this for policy servers that are spawned by the
+Postfix master daemon. On many systems, "local" is a synonym for "unix".
+
+To create a policy service that listens on a UNIX-domain socket called
+"policy", and that runs under control of the Postfix spawn(8) daemon, you would
+use something like this:
+
+ 1 /etc/postfix/master.cf:
+ 2 policy unix - n n - 0 spawn
+ 3 user=nobody argv=/some/where/policy-server
+ 4
+ 5 /etc/postfix/main.cf:
+ 6 smtpd_recipient_restrictions =
+ 7 ...
+ 8 reject_unauth_destination
+ 9 check_policy_service unix:private/policy
+ 10 ...
+ 11 policy_time_limit = 3600
+ 12 # smtpd_policy_service_request_limit = 1
+
+NOTES:
+
+ * Lines 2-3: this creates the service called "policy" that listens on a UNIX-
+ domain socket. The service is implemented by the Postfix spawn(8) daemon,
+ which executes the policy server program that is specified with the aarrggvv
+ attribute, using the privileges specified with the uusseerr attribute.
+
+ * Line 2: specify a "0" process limit instead of the default "-", to avoid
+ "connection refused" and other problems when you increase the smtpd process
+ limit.
+
+ * Line 8: reject_unauth_destination is not needed here if the mail relay
+ policy is specified with smtpd_relay_restrictions (available with Postfix
+ 2.10 and later).
+
+ * Lines 8, 9: always specify "check_policy_service" AFTER
+ "reject_unauth_destination" or else your system could become an open relay.
+
+ * Line 11: this increases the time that a policy server process may run to
+ 3600 seconds. The default time limit of 1000 seconds is too short; the
+ policy daemon needs to run as long as the SMTP server process that talks to
+ it. See the spawn(8) manpage for more information about the
+ transport_time_limit parameter.
+
+ Note: the "policy_time_limit" parameter will not show up in "postconf"
+ command output before Postfix version 2.9. This limitation applies to
+ many parameters whose name is a combination of a master.cf service name
+ (in the above example, "policy") and a built-in suffix (in the above
+ example: "_time_limit").
+
+ * Line 12: specify smtpd_policy_service_request_limit to avoid error-recovery
+ delays with policy servers that cannot maintain a persistent connection.
+
+ * With Solaris < 9, or Postfix < 2.10 on any Solaris version, use TCP sockets
+ instead of UNIX-domain sockets:
+
+ 1 /etc/postfix/master.cf:
+ 2 127.0.0.1:9998 inet n n n - 0 spawn
+ 3 user=nobody argv=/some/where/policy-server
+ 4
+ 5 /etc/postfix/main.cf:
+ 6 smtpd_recipient_restrictions =
+ 7 ...
+ 8 reject_unauth_destination
+ 9 check_policy_service inet:127.0.0.1:9998
+ 10 ...
+ 11 127.0.0.1:9998_time_limit = 3600
+ 12 # smtpd_policy_service_request_limit = 1
+
+Configuration parameters that control the client side of the policy delegation
+protocol:
+
+ * smtpd_policy_service_default_action (default: 451 4.3.5 Server
+ configuration problem): The default action when an SMTPD policy service
+ request fails. Available with Postfix 3.0 and later.
+
+ * smtpd_policy_service_max_idle (default: 300s): The amount of time before
+ the Postfix SMTP server closes an unused policy client connection.
+
+ * smtpd_policy_service_max_ttl (default: 1000s): The amount of time before
+ the Postfix SMTP server closes an active policy client connection.
+
+ * smtpd_policy_service_request_limit (default: 0): The maximal number of
+ requests per policy connection, or zero (no limit). Available with Postfix
+ 3.0 and later.
+
+ * smtpd_policy_service_timeout (default: 100s): The time limit to connect to,
+ send to or receive from a policy server.
+
+ * smtpd_policy_service_try_limit (default: 2): The maximal number of attempts
+ to send an SMTPD policy service request before giving up. Available with
+ Postfix 3.0 and later.
+
+ * smtpd_policy_service_retry_delay (default: 1s): The delay between attempts
+ to resend a failed SMTPD policy service request. Available with Postfix 3.0
+ and later.
+
+ * smtpd_policy_service_policy_context (default: empty): Optional information
+ that is passed in the "policy_context" attribute of an SMTPD policy service
+ request (originally, to share the same SMTPD service endpoint among
+ multiple check_policy_service clients). Available with Postfix 3.1 and
+ later.
+
+Configuration parameters that control the server side of the policy delegation
+protocol:
+
+ * transport_time_limit ($command_time_limit): The maximal amount of time the
+ policy daemon is allowed to run before it is terminated. The transport is
+ the service name of the master.cf entry for the policy daemon service. In
+ the above examples, the service name is "policy" or "127.0.0.1:9998".
+
+AAddvvaanncceedd ppoolliiccyy cclliieenntt ccoonnffiigguurraattiioonn
+
+The previous section lists a number of Postfix main.cf parameters that control
+time limits and other settings for all policy clients. This is sufficient for
+simple configurations. With more complex configurations it becomes desirable to
+have different settings per policy client. This is supported with Postfix 3.0
+and later.
+
+The following example shows a "non-critical" policy service with a short
+timeout, and with "DUNNO" as default action when the service is unvailable. The
+"DUNNO" action causes Postfix to ignore the result.
+
+ 1 /etc/postfix/main.cf:
+ 2 mua_recipient_restrictions =
+ 3 ...
+ 4 reject_unauth_destination
+ 5 check_policy_service { inet:host:port,
+ 6 timeout=10s, default_action=DUNNO
+ 7 policy_context=submission }
+ 8 ...
+
+Instead of a server endpoint, we now have a list enclosed in {}.
+
+ * Line 5: The first item in the list is the server endpoint. This supports
+ the exact same "inet" and "unix" syntax as described earlier.
+
+ * Line 6-7: The remainder of the list contains per-client settings. These
+ settings override global main.cf parameters, and have the same name as
+ those parameters, without the "smtpd_policy_service_" prefix.
+
+Inside the list, syntax is similar to what we already know from main.cf: items
+separated by space or comma. There is one difference: yyoouu mmuusstt eenncclloossee aa
+sseettttiinngg iinn ppaarreenntthheesseess,, aass iinn ""{{ nnaammee == vvaalluuee }}"",, iiff yyoouu wwaanntt ttoo hhaavvee ssppaaccee oorr
+ccoommmmaa wwiitthhiinn aa vvaalluuee oorr aarroouunndd ""=="". This comes in handy when different policy
+servers require different default actions with different SMTP status codes or
+text:
+
+ 1 /etc/postfix/main.cf:
+ 2 smtpd_recipient_restrictions =
+ 3 ...
+ 4 reject_unauth_destination
+ 5 check_policy_service {
+ 6 inet:host:port1,
+ 7 { default_action = 451 4.3.5 See http://www.example.com/
+ support1 }
+ 8 }
+ 9 ...
+
+EExxaammppllee:: ggrreeyylliisstt ppoolliiccyy sseerrvveerr
+
+Greylisting is a defense against junk email that is described at http://
+www.greylisting.org/. The idea was discussed on the postfix-users mailing list
+one year before it was popularized.
+
+The file examples/smtpd-policy/greylist.pl in the Postfix source tree
+implements a simplified greylist policy server. This server stores a time stamp
+for every (client, sender, recipient) triple. By default, mail is not accepted
+until a time stamp is more than 60 seconds old. This stops junk mail with
+randomly selected sender addresses, and mail that is sent through randomly
+selected open proxies. It also stops junk mail from spammers that change their
+IP address frequently.
+
+Copy examples/smtpd-policy/greylist.pl to /usr/libexec/postfix or whatever
+location is appropriate for your system.
+
+In the greylist.pl Perl script you need to specify the location of the greylist
+database file, and how long mail will be delayed before it is accepted. The
+default settings are:
+
+ $database_name="/var/mta/greylist.db";
+ $greylist_delay=60;
+
+The /var/mta directory (or whatever you choose) should be writable by "nobody",
+or by whatever username you configure below in master.cf for the policy
+service.
+
+Example:
+
+ # mkdir /var/mta
+ # chown nobody /var/mta
+
+Note: DO NOT create the greylist database in a world-writable directory such as
+/tmp or /var/tmp, and DO NOT create the greylist database in a file system that
+may run out of space. Postfix can survive "out of space" conditions with the
+mail queue and with the mailbox store, but it cannot survive a corrupted
+greylist database. If the file becomes corrupted you may not be able to receive
+mail at all until you delete the file by hand.
+
+The greylist.pl Perl script can be run under control by the Postfix master
+daemon. For example, to run the script as user "nobody", using a UNIX-domain
+socket that is accessible by Postfix processes only:
+
+ 1 /etc/postfix/master.cf:
+ 2 greylist unix - n n - 0 spawn
+ 3 user=nobody argv=/usr/bin/perl /usr/libexec/postfix/greylist.pl
+ 4
+ 5 /etc/postfix/main.cf:
+ 6 greylist_time_limit = 3600
+ 7 smtpd_recipient_restrictions =
+ 8 ...
+ 9 reject_unauth_destination
+ 10 check_policy_service unix:private/greylist
+ 11 ...
+ 12 # smtpd_policy_service_request_limit = 1
+
+Notes:
+
+ * Lines 2-3: this creates the service called "greylist" that listens on a
+ UNIX-domain socket. The service is implemented by the Postfix spawn(8)
+ daemon, which executes the greylist.pl script that is specified with the
+ aarrggvv attribute, using the privileges specified with the uusseerr attribute.
+
+ * Line 2: specify a "0" process limit instead of the default "-", to avoid
+ "connection refused" and other problems when you increase the smtpd process
+ limit.
+
+ * Line 3: Specify "greylist.pl -v" for verbose logging of each request and
+ reply.
+
+ * Line 6: this increases the time that a greylist server process may run to
+ 3600 seconds. The default time limit of 1000 seconds is too short; the
+ greylist daemon needs to run as long as the SMTP server process that talks
+ to it. See the spawn(8) manpage for more information about the
+ transport_time_limit parameter.
+
+ * Line 9: reject_unauth_destination is not needed here if the mail relay
+ policy is specified with smtpd_relay_restrictions (available with Postfix
+ 2.10 and later).
+
+ Note: the "greylist_time_limit" parameter will not show up in
+ "postconf" command output before Postfix version 2.9. This limitation
+ applies to many parameters whose name is a combination of a master.cf
+ service name (in the above example, "greylist") and a built-in suffix
+ (in the above example: "_time_limit").
+
+ * Line 12: specify smtpd_policy_service_request_limit to avoid error-recovery
+ delays with policy servers that cannot maintain a persistent connection.
+
+With Solaris < 9, or Postfix < 2.10 on any Solaris version, use inet: style
+sockets instead of unix: style, as detailed in the "Policy client/server
+configuration" section above.
+
+ 1 /etc/postfix/master.cf:
+ 2 127.0.0.1:9998 inet n n n - 0 spawn
+ 3 user=nobody argv=/usr/bin/perl /usr/libexec/postfix/greylist.pl
+ 4
+ 5 /etc/postfix/main.cf:
+ 6 127.0.0.1:9998_time_limit = 3600
+ 7 smtpd_recipient_restrictions =
+ 8 ...
+ 9 reject_unauth_destination
+ 10 check_policy_service inet:127.0.0.1:9998
+ 11 ...
+ 12 # smtpd_policy_service_request_limit = 1
+
+GGrreeyylliissttiinngg mmaaiill ffrroomm ffrreeqquueennttllyy ffoorrggeedd ddoommaaiinnss
+
+It is relatively safe to turn on greylisting for specific domains that often
+appear in forged email. At some point in cyberspace/time a list of frequently
+forged MAIL FROM domains could be found at https://web.archive.org/web/
+20080526153208/http://www.monkeys.com/anti-spam/filtering/sender-domain-
+validate.in.
+
+ 1 /etc/postfix/main.cf:
+ 2 smtpd_recipient_restrictions =
+ 3 reject_unlisted_recipient
+ 4 ...
+ 5 reject_unauth_destination
+ 6 check_sender_access hash:/etc/postfix/sender_access
+ 7 ...
+ 8 smtpd_restriction_classes = greylist
+ 9 greylist = check_policy_service unix:private/greylist
+ 10
+ 11 /etc/postfix/sender_access:
+ 12 aol.com greylist
+ 13 hotmail.com greylist
+ 14 bigfoot.com greylist
+ 15 ... etcetera ...
+
+NOTES:
+
+ * Line 9: On Solaris < 9, or Postfix < 2.10 on any Solaris version, use inet:
+ style sockets instead of unix: style, as detailed in the "Example: greylist
+ policy server" section above.
+
+ * Line 5: reject_unauth_destination is not needed here if the mail relay
+ policy is specified with smtpd_relay_restrictions (available with Postfix
+ 2.10 and later).
+
+ * Line 6: Be sure to specify "check_sender_access" AFTER
+ "reject_unauth_destination" or else your system could become an open mail
+ relay.
+
+ * Line 3: With Postfix 2.0 snapshot releases, "reject_unlisted_recipient" is
+ called "check_recipient_maps". Postfix 2.1 understands both forms.
+
+ * Line 3: The greylist database gets polluted quickly with bogus addresses.
+ It helps if you protect greylist lookups with other restrictions that
+ reject unknown senders and/or recipients.
+
+GGrreeyylliissttiinngg aallll yyoouurr mmaaiill
+
+If you turn on greylisting for all mail you may want to make exceptions for
+mailing lists that use one-time sender addresses, because each message will be
+delayed due to greylisting, and the one-time sender addresses can pollute your
+greylist database relatively quickly. Instead of making exceptions, you can
+automatically allowlist clients that survive greylisting repeatedly; this
+avoids most of the delays and most of the database pollution problem.
+
+ 1 /etc/postfix/main.cf:
+ 2 smtpd_recipient_restrictions =
+ 3 reject_unlisted_recipient
+ 4 ...
+ 5 reject_unauth_destination
+ 6 check_sender_access hash:/etc/postfix/sender_access
+ 7 check_policy_service unix:private/policy
+ 8 ...
+ 9
+ 10 /etc/postfix/sender_access:
+ 11 securityfocus.com OK
+ 12 ...
+
+NOTES:
+
+ * Line 7: On Solaris < 9, or Postfix < 2.10 on any Solaris version, use inet:
+ style sockets instead of unix: style, as detailed in the "Example: greylist
+ policy server" section above.
+
+ * Line 5: reject_unauth_destination is not needed here if the mail relay
+ policy is specified with smtpd_relay_restrictions (available with Postfix
+ 2.10 and later).
+
+ * Lines 6-7: Be sure to specify check_sender_access and check_policy_service
+ AFTER reject_unauth_destination or else your system could become an open
+ mail relay.
+
+ * Line 3: The greylist database gets polluted quickly with bogus addresses.
+ It helps if you precede greylist lookups with restrictions that reject
+ unknown senders and/or recipients.
+
+RRoouuttiinnee ggrreeyylliisstt mmaaiinntteennaannccee
+
+The greylist database grows over time, because the greylist server never
+removes database entries. If left unattended, the greylist database will
+eventually run your file system out of space.
+
+When the status file size exceeds some threshold you can simply rename or
+remove the file without adverse effects; Postfix automatically creates a new
+file. In the worst case, new mail will be delayed by an hour or so. To lessen
+the impact, rename or remove the file in the middle of the night at the
+beginning of a weekend.
+
+EExxaammppllee PPeerrll ggrreeyylliisstt sseerrvveerr
+
+This is the Perl subroutine that implements the example greylist policy. It is
+part of a general purpose sample policy server that is distributed with the
+Postfix source as examples/smtpd-policy/greylist.pl.
+
+#
+# greylist status database and greylist time interval. DO NOT create the
+# greylist status database in a world-writable directory such as /tmp
+# or /var/tmp. DO NOT create the greylist database in a file system
+# that can run out of space.
+#
+$database_name="/var/mta/greylist.db";
+$greylist_delay=60;
+
+#
+# Auto-allowlist threshold. Specify 0 to disable, or the number of
+# successful "come backs" after which a client is no longer subject
+# to greylisting.
+#
+$auto_allowlist_threshold = 10;
+
+#
+# Demo SMTPD access policy routine. The result is an action just like
+# it would be specified on the right-hand side of a Postfix access
+# table. Request attributes are available via the %attr hash.
+#
+sub smtpd_access_policy {
+ my($key, $time_stamp, $now);
+
+ # Open the database on the fly.
+ open_database() unless $database_obj;
+
+ # Search the auto-allowlist.
+ if ($auto_allowlist_threshold > 0) {
+ $count = read_database($attr{"client_address"});
+ if ($count > $auto_allowlist_threshold) {
+ return "dunno";
+ }
+ }
+
+ # Lookup the time stamp for this client/sender/recipient.
+ $key =
+ lc $attr{"client_address"}."/".$attr{"sender"}."/".$attr{"recipient"};
+ $time_stamp = read_database($key);
+ $now = time();
+
+ # If new request, add this client/sender/recipient to the database.
+ if ($time_stamp == 0) {
+ $time_stamp = $now;
+ update_database($key, $time_stamp);
+ }
+
+ # The result can be any action that is allowed in a Postfix access(5) map.
+ #
+ # To label the mail, return ``PREPEND headername: headertext''
+ #
+ # In case of success, return ``DUNNO'' instead of ``OK'', so that the
+ # check_policy_service restriction can be followed by other restrictions.
+ #
+ # In case of failure, return ``DEFER_IF_PERMIT optional text...'',
+ # so that mail can still be blocked by other access restrictions.
+ #
+ syslog $syslog_priority, "request age %d", $now - $time_stamp if $verbose;
+ if ($now - $time_stamp > $greylist_delay) {
+ # Update the auto-allowlist.
+ if ($auto_allowlist_threshold > 0) {
+ update_database($attr{"client_address"}, $count + 1);
+ }
+ return "dunno";
+ } else {
+ return "defer_if_permit Service temporarily unavailable";
+ }
+}
+