Implemented dmarc_addresses feature.
[mailman.git] / src / mailman / rules / docs / dmarc-mitigation.rst
blob534614870a77f0e24e78c9048b0b05b4bcc0d0c0
1 ================
2 DMARC mitigation
3 ================
5 This rule only matches in order to jump to the moderation chain to reject or
6 discard the message.  The rule looks at the list's ``dmarc_mitigate_action``
7 and if it is other than ``no_mitigation``, it checks the domain of the
8 ``From:`` address for a DMARC policy.  Depending on various settings, reject
9 or discard the message, or just flag it for the dmarc handler to apply DMARC
10 mitigations to the message.
12     >>> from mailman.app.lifecycle import create_list
13     >>> mlist = create_list('ant@example.com')
14     >>> from mailman.config import config    
15     >>> rule = config.rules['dmarc-mitigation']
16     >>> print(rule.name)
17     dmarc-mitigation
19 First we set up a mock to return predictable responses to DNS lookups.  This
20 returns ``p=reject`` for the ``example.biz`` domain and not for any others.
22     >>> from mailman.rules.tests.test_dmarc import get_dns_resolver
23     >>> ignore = cleanups.enter_context(get_dns_resolver())
25 Use test data for the organizational domain suffixes.
27     >>> from mailman.rules.tests.test_dmarc import use_test_organizational_data
28     >>> ignore = use_test_organizational_data(cleanups)
30 A message ``From:`` a domain without a DMARC policy does not set any flags.
32     >>> from mailman.interfaces.mailinglist import DMARCMitigateAction
33     >>> mlist.dmarc_mitigate_action = DMARCMitigateAction.munge_from
34     >>> from mailman.testing.helpers import (specialized_message_from_string
35     ...   as message_from_string)
36     >>> msg = message_from_string("""\
37     ... From: aperson@example.org
38     ... To: ant@example.com
39     ... Subject: A posted message
40     ...
41     ... """)
42     >>> msgdata = {}
43     >>> rule.check(mlist, msg, msgdata)
44     False
45     >>> msgdata
46     {}
48 Even if the ``From:`` domain publishes ``p=reject``, no flags are set if the
49 list's action is ``no_mitigation``.
51     >>> mlist.dmarc_mitigate_action = DMARCMitigateAction.no_mitigation
52     >>> msg = message_from_string("""\
53     ... From: aperson@example.biz
54     ... To: ant@example.com
55     ... Subject: A posted message
56     ...
57     ... """)
58     >>> msgdata = {}
59     >>> rule.check(mlist, msg, msgdata)
60     False
61     >>> msgdata
62     {}
64 With a mitigation strategy chosen, the message is flagged.
66     >>> mlist.dmarc_mitigate_action = DMARCMitigateAction.munge_from
67     >>> msg = message_from_string("""\
68     ... From: aperson@example.biz
69     ... To: ant@example.com
70     ... Subject: A posted message
71     ...
72     ... """)
73     >>> msgdata = {}
74     >>> rule.check(mlist, msg, msgdata)
75     False
76     >>> msgdata
77     {'dmarc': True}
79 Subdomains which don't have a policy will check the organizational domain.
81     >>> msg = message_from_string("""\
82     ... From: aperson@sub.domain.example.biz
83     ... To: ant@example.com
84     ... Subject: A posted message
85     ...
86     ... """)
87     >>> msgdata = {}
88     >>> rule.check(mlist, msg, msgdata)
89     False
90     >>> msgdata
91     {'dmarc': True}
93 We can set an address or regexp to apply DMARC mitigations regardless of the
94 domains policy.
96     >>> mlist.dmarc_mitigate_action = DMARCMitigateAction.munge_from
97     >>> msg = message_from_string("""\
98     ... From: aperson@example.com
99     ... To: ant@example.com
100     ... Subject: A posted message
101     ...
102     ... """)
103     >>> msgdata = {}
104     >>> mlist.dmarc_addresses = ['^.*@example.com']
105     >>> rule.check(mlist, msg, msgdata)
106     False
107     >>> msgdata
108     {'dmarc': True}
110 The list's action can also be set to immediately discard or reject the
111 message.
113     >>> mlist.dmarc_mitigate_action = DMARCMitigateAction.discard
114     >>> msg = message_from_string("""\
115     ... From: aperson@example.biz
116     ... To: ant@example.com
117     ... Subject: A posted message
118     ... Message-ID: <xxx_message_id@example.biz>
119     ...
120     ... """)
121     >>> msgdata = {}
122     >>> rule.check(mlist, msg, msgdata)
123     True
124     >>> from mailman.testing.documentation import dump_msgdata    
125     >>> dump_msgdata(msgdata)
126     dmarc             : True
127     dmarc_action      : discard
128     moderation_reasons: ['DMARC moderation']
129     moderation_sender : aperson@example.biz
131 We can reject the message with a default reason.
133     >>> mlist.dmarc_mitigate_action = DMARCMitigateAction.reject
134     >>> msg = message_from_string("""\
135     ... From: aperson@example.biz
136     ... To: ant@example.com
137     ... Subject: A posted message
138     ... Message-ID: <xxx_message_id@example.biz>
139     ...
140     ... """)
141     >>> msgdata = {}
142     >>> rule.check(mlist, msg, msgdata)
143     True
144     >>> dump_msgdata(msgdata)
145     dmarc             : True
146     dmarc_action      : reject
147     moderation_reasons: ['You are not allowed to post to this mailing list...
148     moderation_sender : aperson@example.biz
150 And, we can reject with a custom message.
152     >>> mlist.dmarc_moderation_notice = 'A silly reason'
153     >>> msg = message_from_string("""\
154     ... From: aperson@example.biz
155     ... To: ant@example.com
156     ... Subject: A posted message
157     ... Message-ID: <xxx_message_id@example.biz>
158     ...
159     ... """)
160     >>> msgdata = {}
161     >>> rule.check(mlist, msg, msgdata)
162     True
163     >>> dump_msgdata(msgdata)
164     dmarc             : True
165     dmarc_action      : reject
166     moderation_reasons: ['A silly reason']
167     moderation_sender : aperson@example.biz