diff options
| -rw-r--r-- | src/mailman/chains/builtin.py | 6 | ||||
| -rw-r--r-- | src/mailman/rules/dmarc.py | 23 | ||||
| -rw-r--r-- | src/mailman/rules/docs/dmarc-moderation.rst | 123 |
3 files changed, 32 insertions, 120 deletions
diff --git a/src/mailman/chains/builtin.py b/src/mailman/chains/builtin.py index f31fb6ed2..76b4716c7 100644 --- a/src/mailman/chains/builtin.py +++ b/src/mailman/chains/builtin.py @@ -38,8 +38,10 @@ class BuiltInChain: description = _('The built-in moderation chain.') _link_descriptions = ( - # First check DMARC and maybe reject or discard. - ('dmarc-moderation', LinkAction.defer, None), + # First check DMARC. For a reject or discard, the rule hits and we + # jump to the moderation chain to do the action. Otherwise, the rule + # misses buts sets msgdata['dmarc'] for the handler. + ('dmarc-moderation', LinkAction.jump, 'moderation'), ('approved', LinkAction.jump, 'accept'), ('emergency', LinkAction.jump, 'hold'), ('loop', LinkAction.jump, 'discard'), diff --git a/src/mailman/rules/dmarc.py b/src/mailman/rules/dmarc.py index 67a8d9045..b22d50ea3 100644 --- a/src/mailman/rules/dmarc.py +++ b/src/mailman/rules/dmarc.py @@ -25,8 +25,6 @@ from dns.exception import DNSException from email.utils import parseaddr from lazr.config import as_timedelta from mailman import public -from mailman.chains.discard import DiscardChain -from mailman.chains.reject import RejectChain from mailman.config import config from mailman.core.i18n import _ from mailman.interfaces.mailinglist import DMARCModerationAction @@ -246,14 +244,15 @@ class DMARCModeration: return False dn, addr = parseaddr(msg.get('from')) if _IsDMARCProhibited(mlist, addr): - # This is something of a kludge, but we can't have this rule be - # a chain in the normal way, because a hit will cause the message - # to be held. We just flag the hit for the handler, but jump - # to the reject or discard chain if appropriate. + # If dmarc_moderation_action is discard or reject, this rule fires + # and jumps to the 'moderation' chain to do the actual discard. + # Otherwise, the rule misses but sets a flag for the dmarc handler + # to do the appropriate action. msgdata['dmarc'] = True if mlist.dmarc_moderation_action == DMARCModerationAction.discard: - DiscardChain()._process(mlist, msg, msgdata) - if mlist.dmarc_moderation_action == DMARCModerationAction.reject: + msgdata['moderation_action'] = 'discard' + msgdata['moderation_reasons'] = _('DMARC moderation') + elif mlist.dmarc_moderation_action == DMARCModerationAction.reject: listowner = mlist.owner_address # noqa F841 reason = (mlist.dmarc_moderation_notice or _('You are not allowed to post to this mailing ' @@ -263,7 +262,9 @@ class DMARCModeration: 'that your messages are being rejected in error, ' 'contact the mailing list owner at ${listowner}.')) msgdata['moderation_reasons'] = [wrap(reason)] - # Add the hit for the reject notice. - msgdata.setdefault('rule_hits', []).append('dmarc-moderation') - RejectChain()._process(mlist, msg, msgdata) + msgdata['moderation_action'] = 'reject' + else: + return False + msgdata['moderation_sender'] = addr + return True return False diff --git a/src/mailman/rules/docs/dmarc-moderation.rst b/src/mailman/rules/docs/dmarc-moderation.rst index fb9ac3ac5..c2210011a 100644 --- a/src/mailman/rules/docs/dmarc-moderation.rst +++ b/src/mailman/rules/docs/dmarc-moderation.rst @@ -78,12 +78,6 @@ Subdomains which don't have a policy will check the organizational domain. The list's action can also be set to immediately discard or reject the message. - >>> from mailman.interfaces.chain import ChainEvent - >>> from mailman.testing.helpers import event_subscribers - >>> def handler(event): - ... if isinstance(event, ChainEvent): - ... print(event.__class__.__name__, - ... event.chain.name, event.msg['message-id']) >>> mlist.dmarc_moderation_action = DMARCModerationAction.discard >>> msg = message_from_string("""\ ... From: aperson@yahoo.com @@ -93,12 +87,12 @@ message. ... ... """) >>> msgdata = {} - >>> with event_subscribers(handler): - ... rule.check(mlist, msg, msgdata) - DiscardEvent discard <xxx_message_id@yahoo.com> - False + >>> rule.check(mlist, msg, msgdata) + True >>> msgdata['dmarc'] True + >>> msgdata['moderation_action'] + 'discard' We can reject the message with a default reason. @@ -111,59 +105,14 @@ We can reject the message with a default reason. ... ... """) >>> msgdata = {} - >>> with event_subscribers(handler): - ... rule.check(mlist, msg, msgdata) - RejectEvent reject <xxx_message_id@yahoo.com> - False + >>> rule.check(mlist, msg, msgdata) + True >>> msgdata['dmarc'] True - -There is now a reject message in the virgin queue. - - >>> from mailman.testing.helpers import get_queue_messages - >>> messages = get_queue_messages('virgin') - >>> len(messages) - 1 - >>> print(messages[0].msg.as_string()) - Subject: A posted message - From: _xtest-owner@example.com - To: aperson@yahoo.com - MIME-Version: 1.0 - Content-Type: multipart/mixed; boundary="..." - Message-ID: <...> - Date: ... - Precedence: bulk - <BLANKLINE> - --... - Content-Type: text/plain; charset="us-ascii" - MIME-Version: 1.0 - Content-Transfer-Encoding: 7bit - <BLANKLINE> - <BLANKLINE> - Your message to the _xtest mailing-list was rejected for the following - reasons: - <BLANKLINE> - You are not allowed to post to this mailing list From: a domain which - publishes a DMARC policy of reject or quarantine, and your message has - been automatically rejected. If you think that your messages are - being rejected in error, contact the mailing list owner at - _xtest-owner@example.com. - <BLANKLINE> - The original message as received by Mailman is attached. - <BLANKLINE> - --... - Content-Type: message/rfc822 - MIME-Version: 1.0 - <BLANKLINE> - From: aperson@yahoo.com - To: _xtest@example.com - Subject: A posted message - Message-ID: <xxx_message_id@yahoo.com> - X-Mailman-Rule-Hits: dmarc-moderation - <BLANKLINE> - <BLANKLINE> - --...-- - <BLANKLINE> + >>> msgdata['moderation_action'] + 'reject' + >>> msgdata['moderation_reasons'] + ['You are not allowed to post to this mailing list From: a domain ... And, we can reject with a custom message. @@ -176,51 +125,11 @@ And, we can reject with a custom message. ... ... """) >>> msgdata = {} - >>> with event_subscribers(handler): - ... rule.check(mlist, msg, msgdata) - RejectEvent reject <xxx_message_id@yahoo.com> - False + >>> rule.check(mlist, msg, msgdata) + True >>> msgdata['dmarc'] True - -Check the the virgin queue. - - >>> messages = get_queue_messages('virgin') - >>> len(messages) - 1 - >>> print(messages[0].msg.as_string()) - Subject: A posted message - From: _xtest-owner@example.com - To: aperson@yahoo.com - MIME-Version: 1.0 - Content-Type: multipart/mixed; boundary="..." - Message-ID: <...> - Date: ... - Precedence: bulk - <BLANKLINE> - --... - Content-Type: text/plain; charset="us-ascii" - MIME-Version: 1.0 - Content-Transfer-Encoding: 7bit - <BLANKLINE> - <BLANKLINE> - Your message to the _xtest mailing-list was rejected for the following - reasons: - <BLANKLINE> - A silly reason - <BLANKLINE> - The original message as received by Mailman is attached. - <BLANKLINE> - --... - Content-Type: message/rfc822 - MIME-Version: 1.0 - <BLANKLINE> - From: aperson@yahoo.com - To: _xtest@example.com - Subject: A posted message - Message-ID: <xxx_message_id@yahoo.com> - X-Mailman-Rule-Hits: dmarc-moderation - <BLANKLINE> - <BLANKLINE> - --...-- - <BLANKLINE> + >>> msgdata['moderation_action'] + 'reject' + >>> msgdata['moderation_reasons'] + ['A silly reason'] |
