File: Result.pm

package info (click to toggle)
libmail-dmarc-perl 1.20211209-4
  • links: PTS
  • area: main
  • in suites: bookworm
  • size: 1,724 kB
  • sloc: perl: 4,937; xml: 13; makefile: 10; sh: 1
file content (206 lines) | stat: -rw-r--r-- 5,749 bytes parent folder | download
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
package Mail::DMARC::Result;
our $VERSION = '1.20211209';
use strict;
use warnings;

use Carp;
require Mail::DMARC::Result::Reason;

sub new {
    my $class = shift;
    return bless {
        dkim => '',
        spf  => '',
        reason => [],
        },
        $class;
}

sub published {
    my ( $self, $policy ) = @_;

    if ( !$policy ) {
        if ( !defined $self->{published} ) {
            croak
                "no policy discovered. Did you validate(), or at least fetch_dmarc_record() first? Or inspected results to detect a 'No Results Found' type error?";
        }
        return $self->{published};
    }

    $policy->{domain}
        or croak
        "tag the policy object with a domain indicating where the DMARC record was found!";
    return $self->{published} = $policy;
}

sub disposition {
    return $_[0]->{disposition} if 1 == scalar @_;
    croak "invalid disposition ($_[1]"
        if 0 == grep {/^$_[1]$/ix} qw/ reject quarantine none /;
    return $_[0]->{disposition} = $_[1];
}

sub dkim {
    return $_[0]->{dkim} if 1 == scalar @_;
    croak "invalid dkim" if 0 == grep {/^$_[1]$/ix} qw/ pass fail /;
    return $_[0]->{dkim} = $_[1];
}

sub dkim_align {
    return $_[0]->{dkim_align} if 1 == scalar @_;
    croak "invalid dkim_align"
        if 0 == grep {/^$_[1]$/ix} qw/ relaxed strict /;
    return $_[0]->{dkim_align} = $_[1];
}

sub dkim_meta {
    return $_[0]->{dkim_meta} if 1 == scalar @_;
    return $_[0]->{dkim_meta} = $_[1];
}

sub spf {
    return $_[0]->{spf} if 1 == scalar @_;
    croak "invalid spf" if 0 == grep {/^$_[1]$/ix} qw/ pass fail /;
    return $_[0]->{spf} = $_[1];
}

sub spf_align {
    return $_[0]->{spf_align} if 1 == scalar @_;
    croak "invalid spf_align" if 0 == grep {/^$_[1]$/ix} qw/ relaxed strict /;
    return $_[0]->{spf_align} = $_[1];
}

sub result {
    return $_[0]->{result} if 1 == scalar @_;
    croak "invalid result" if 0 == grep {/^$_[1]$/ix} qw/ pass fail none /;
    return $_[0]->{result} = $_[1];
}

sub reason {
    my ($self, @args) = @_;
    return $self->{reason} if ! scalar @args;
    push @{ $self->{reason}}, Mail::DMARC::Result::Reason->new(@args);
    return $self->{reason};
}

1;

__END__

=pod

=head1 NAME

Mail::DMARC::Result - an aggregate report result object

=head1 VERSION

version 1.20211209

=head1 OVERVIEW

A L<Result|Mail::DMARC::Result> object is the product of instantiating a L<DMARC::PurePerl|Mail::DMARC::PurePerl> object, populating the variables, and running $dmarc->validate. The results object looks like this:

    result       => 'pass',   # pass, fail
    disposition  => 'none',   # reject, quarantine, none
    reason       => [         # there can be many reasons...
            {
                type     => '',   # forwarded, sampled_out, trusted_forwarder,
                comment  => '',   #   mailing_list, local_policy, other
            },
        ],
    dkim         => 'pass',   # pass, fail
    dkim_align   => 'strict', # strict, relaxed
    spf          => 'pass',   # pass, fail
    spf_align    => 'strict', # strict, relaxed
    published    => L<Mail::DMARC::Policy>,

Reasons are optional and may not be present.

The dkim_align and spf_align fields will only be present if the corresponding test value equals pass. They are additional info not specified by the DMARC spec.

=head1 METHODS

=head2 published

Published is a L<Mail::DMARC::Policy> tagged with a domain. The domain attribute is the DNS domain name where the DMARC record was found. This may not be the same as the header_from domain (ex: bounces.amazon.com -vs- amazon.com).

=head2 result

Whether the message passed the DMARC test. Possible values are: pass, fail.

In order to pass, at least one authentication alignment must pass. The 2013 draft defines two authentication methods: DKIM and SPF. The list is expected to grow.

=head2 disposition

When the DMARC result is not I<pass>, disposition is the results of applying DMARC policy to a message. Generally this is the same as the header_from domains published DMARC L<policy|Mail::DMARC::Policy>. When it is not, the reason SHOULD be specified.

=head2 dkim

Whether the message passed or failed DKIM alignment. In order to pass the DMARC DKIM alignment test, a DKIM signature that matches the RFC5322.From domain must be present. An unsigned messsage, a message with an invalid signature, or signatures that don't match the RFC5322.From field are all considered failures.

=head2 dkim_align

If the message passed the DKIM alignment test, this indicates whether the alignment was strict or relaxed.

=head2 spf

Whether the message passed or failed SPF alignment. To pass SPF alignment, the RFC5321.MailFrom domain must match the RFC5322.From field.

=head2 spf_align

If the message passed the SPF alignment test, this indicates whether the alignment was strict or relaxed.

=head2 reason

If the applied policy differs from the sites published policy, the result policy should contain a reason and optionally a comment.

A DMARC result reason has two attributes, type, and comment.

    reason => {
        type =>  '',
        comment => '',
    },

=head3 type

The following reason types are defined and valid:

    forwarded
    sampled_out
    trusted_forwarder
    mailing_list
    local_policy
    other

=head3 comment

Comment is a free form text field.

=head1 AUTHORS

=over 4

=item *

Matt Simerson <msimerson@cpan.org>

=item *

Davide Migliavacca <shari@cpan.org>

=item *

Marc Bradshaw <marc@marcbradshaw.net>

=back

=head1 COPYRIGHT AND LICENSE

This software is copyright (c) 2021 by Matt Simerson.

This is free software; you can redistribute it and/or modify it under
the same terms as the Perl 5 programming language system itself.

=cut