6
6
use serde:: { Deserialize , Serialize } ;
7
7
use std:: net:: IpAddr ;
8
8
9
+ /// The time range in UTC covered by messages in this report.
10
+ /// Specified in seconds since epoch.
9
11
#[ derive( Debug , Serialize , Deserialize ) ]
10
12
pub struct DateRangeType {
11
13
pub begin : u64 ,
12
14
pub end : u64 ,
13
15
}
14
16
17
+ /// Report generator metadata.
15
18
#[ derive( Debug , Serialize , Deserialize ) ]
16
19
pub struct ReportMetadataType {
17
20
pub org_name : String ,
@@ -24,6 +27,7 @@ pub struct ReportMetadataType {
24
27
pub error : Option < Vec < String > > ,
25
28
}
26
29
30
+ /// Alignment mode for DKIM and SPF.
27
31
#[ derive( Debug , Serialize , Deserialize , PartialEq ) ]
28
32
pub enum AlignmentType {
29
33
#[ serde( rename = "r" ) ]
@@ -32,51 +36,81 @@ pub enum AlignmentType {
32
36
Strict ,
33
37
}
34
38
39
+ /// The policy actions specified by `p` and `sp` in the DMARC record.
35
40
#[ derive( Debug , Serialize , Deserialize , PartialEq ) ]
36
41
#[ serde( rename_all = "snake_case" ) ]
37
42
pub enum DispositionType {
38
43
/// There is no preference on how a failed DMARC should be handled.
39
44
None ,
40
- /// The message should be quarantined. This usually means it will be placed in the `spam` folder of the user.
45
+ /// The message should be quarantined.
46
+ /// This usually means it will be placed in the spam folder of the user.
41
47
Quarantine ,
42
48
/// The message should be rejected.
43
49
Reject ,
44
50
}
45
51
52
+ /// The DMARC policy that applied to the messages in this report.
46
53
#[ derive( Debug , Serialize , Deserialize ) ]
47
54
pub struct PolicyPublishedType {
55
+ /// The domain at which the DMARC record was found.
48
56
pub domain : String ,
57
+ /// The DKIM alignment mode.
49
58
#[ serde( skip_serializing_if = "Option::is_none" ) ]
50
59
pub adkim : Option < AlignmentType > ,
60
+ /// The SPF alignment mode.
51
61
#[ serde( skip_serializing_if = "Option::is_none" ) ]
52
62
pub aspf : Option < AlignmentType > ,
63
+ /// The policy to apply to messages from the domain.
53
64
pub p : DispositionType ,
65
+ /// The policy to apply to messages from subdomains.
54
66
#[ serde( skip_serializing_if = "Option::is_none" ) ]
55
67
pub sp : Option < DispositionType > ,
68
+ /// The percent of messages to which policy applies.
56
69
#[ serde( skip_serializing_if = "Option::is_none" ) ]
57
70
pub pct : Option < u8 > ,
71
+ /// Failure reporting options in effect.
58
72
#[ serde( skip_serializing_if = "Option::is_none" ) ]
59
73
pub fo : Option < String > ,
60
74
}
61
75
76
+ /// The DMARC-aligned authentication result.
62
77
#[ derive( Debug , Clone , Serialize , Deserialize , Hash , PartialEq , Eq ) ]
63
78
#[ serde( rename_all = "snake_case" ) ]
64
79
pub enum DmarcResultType {
65
80
Pass ,
66
81
Fail ,
67
82
}
68
83
84
+ /// Reasons that may affect DMARC disposition or execution thereof.
69
85
#[ derive( Debug , Serialize , Deserialize , PartialEq ) ]
70
86
#[ serde( rename_all = "snake_case" ) ]
71
87
pub enum PolicyOverrideType {
88
+ /// The message was relayed via a known forwarder, or local
89
+ /// heuristics identified the message as likely having been forwarded.
90
+ /// There is no expectation that authentication would pass.
72
91
Forwarded ,
92
+ /// The message was exempted from application of policy by
93
+ /// the `pct` setting in the DMARC policy record.
73
94
SampledOut ,
95
+ /// Message authentication failure was anticipated by
96
+ /// other evidence linking the message to a locally maintained list of
97
+ /// known and trusted forwarders.
74
98
TrustedForwarder ,
99
+ /// Local heuristics determined that the message arrived
100
+ /// via a mailing list, and thus authentication of the original
101
+ /// message was not expected to succeed.
75
102
MailingList ,
103
+ /// The Mail Receiver's local policy exempted the message from
104
+ /// being subjected to the Domain Owner's requested policy action.
76
105
LocalPolicy ,
106
+ /// Some policy exception not covered by the other entries in
107
+ /// this list occurred. Additional detail can be found in the
108
+ /// PolicyOverrideReason `comment` field.
77
109
Other ,
78
110
}
79
111
112
+ /// How do we allow report generators to include new classes of override
113
+ /// reasons if they want to be more specific than `other`?
80
114
#[ derive( Debug , Serialize , Deserialize , PartialEq ) ]
81
115
pub struct PolicyOverrideReason {
82
116
#[ serde( rename = "type" ) ]
@@ -85,6 +119,8 @@ pub struct PolicyOverrideReason {
85
119
pub comment : Option < String > ,
86
120
}
87
121
122
+ /// Taking into account everything else in the record,
123
+ /// the results of applying DMARC.
88
124
#[ derive( Debug , Serialize , Deserialize ) ]
89
125
pub struct PolicyEvaluatedType {
90
126
pub disposition : DispositionType ,
@@ -98,20 +134,27 @@ pub struct PolicyEvaluatedType {
98
134
99
135
#[ derive( Debug , Serialize , Deserialize ) ]
100
136
pub struct RowType {
137
+ /// The connecting IP.
101
138
pub source_ip : IpAddr ,
139
+ /// The number of matching messages.
102
140
pub count : usize ,
141
+ /// The DMARC disposition applying to matching messages.
103
142
pub policy_evaluated : PolicyEvaluatedType ,
104
143
}
105
144
106
145
#[ derive( Debug , Serialize , Deserialize ) ]
107
146
pub struct IdentifierType {
147
+ /// The envelope recipient domain.
108
148
#[ serde( skip_serializing_if = "Option::is_none" ) ]
109
149
pub envelope_to : Option < String > ,
150
+ /// The RFC5321.MailFrom domain.
110
151
#[ serde( skip_serializing_if = "Option::is_none" ) ]
111
152
pub envelope_from : Option < String > ,
153
+ /// The RFC5322.From domain.
112
154
pub header_from : String ,
113
155
}
114
156
157
+ /// DKIM verification result, according to RFC 7001 Section 2.6.1.
115
158
#[ derive( Debug , Clone , Serialize , Deserialize , Hash , PartialEq , Eq ) ]
116
159
#[ serde( rename_all = "snake_case" ) ]
117
160
pub enum DkimResultType {
@@ -128,11 +171,15 @@ pub enum DkimResultType {
128
171
129
172
#[ derive( Debug , Serialize , Deserialize , PartialEq ) ]
130
173
pub struct DkimAuthResultType {
174
+ /// The `d` parameter in the signature.
131
175
pub domain : String ,
176
+ /// The `s` parameter in the signature.
132
177
#[ serde( skip_serializing_if = "Option::is_none" ) ]
133
178
pub selector : Option < String > ,
179
+ /// The DKIM verification result.
134
180
pub result : DkimResultType ,
135
181
#[ serde( skip_serializing_if = "Option::is_none" ) ]
182
+ /// Any extra information.
136
183
pub human_result : Option < String > ,
137
184
}
138
185
@@ -161,19 +208,27 @@ pub enum SpfResultType {
161
208
162
209
#[ derive( Debug , Serialize , Deserialize , PartialEq ) ]
163
210
pub struct SpfAuthResultType {
211
+ /// The checked domain.
164
212
pub domain : String ,
213
+ /// The scope of the checked domain.
165
214
#[ serde( skip_serializing_if = "Option::is_none" ) ]
166
215
pub scope : Option < SpfDomainScope > ,
216
+ /// The SPF verification result.
167
217
pub result : SpfResultType ,
168
218
}
169
219
220
+ /// This element contains DKIM and SPF results, uninterpreted with respect to DMARC.
170
221
#[ derive( Debug , Serialize , Deserialize ) ]
171
222
pub struct AuthResultType {
223
+ /// There may be no DKIM signatures, or multiple DKIM signatures.
172
224
#[ serde( skip_serializing_if = "Option::is_none" ) ]
173
225
pub dkim : Option < Vec < DkimAuthResultType > > ,
226
+ /// There will always be at least one SPF result.
174
227
pub spf : Vec < SpfAuthResultType > ,
175
228
}
176
229
230
+ /// This element contains all the authentication results that were
231
+ /// evaluated by the receiving system for the given set of messages.
177
232
#[ derive( Debug , Serialize , Deserialize ) ]
178
233
pub struct RecordType {
179
234
pub row : RowType ,
0 commit comments