File Coverage

blib/lib/Email/Simple/Test/TraceHeaders.pm
Criterion Covered Total %
statement 49 49 100.0
branch 11 12 91.6
condition n/a
subroutine 13 13 100.0
pod 2 2 100.0
total 75 76 98.6


line stmt bran cond sub pod time code
1 1     1   416 use strict;
  1         6  
  1         24  
2 1     1   4 use warnings;
  1         2  
  1         32  
3             package Email::Simple::Test::TraceHeaders 0.091703;
4             # ABSTRACT: generate sample trace headers for testing
5              
6 1     1   4 use Carp ();
  1         2  
  1         27  
7 1     1   359 use Email::Date::Format ();
  1         2874  
  1         19  
8 1     1   376 use Email::Simple;
  1         3882  
  1         25  
9 1     1   5 use Email::Simple::Creator;
  1         2  
  1         16  
10 1     1   403 use Sub::Exporter::Util ();
  1         14775  
  1         40  
11              
12 1         6 use Sub::Exporter -setup => {
13             exports => [ prev => \'_build_prev' ],
14             groups => [ helpers => [ qw(prev) ] ],
15 1     1   6 };
  1         2  
16              
17             # For now, we'll only generate one style of Received header: postfix
18             # It's what I encounter the most, and it's simple and straightforward.
19             # In the future, we'll be flexible, maybe. -- rjbs, 2009-06-19
20             my %POSTFIX_FMT = (
21             for => q{from %s (%s [%s]) by %s (Postfix) with ESMTP id %s for <%s>; %s},
22             nofor => q{from %s (%s [%s]) by %s (Postfix) with ESMTP id %s%s; %s},
23             );
24              
25             #pod =head1 METHODS
26             #pod
27             #pod =head2 trace_headers
28             #pod
29             #pod my $header_strings = Email::Simple::Test::TraceHeaders->trace_headers(\%arg);
30             #pod
31             #pod This returns an arrayref of "Received" header strings.
32             #pod
33             #pod At present, all headers are produced in Postfix style.
34             #pod
35             #pod At present the only valid argument is C, which is an arrayref of hashrefs
36             #pod describing hops. Each hashref should have the following entries:
37             #pod
38             #pod from_helo - the hostname given in the sending host's HELO
39             #pod from_rdns - the hostname found by looking up the PTR for the sender's ip
40             #pod from_ip - the IP addr of the sending host
41             #pod by_name - the hostname of the receiving host
42             #pod queue_id - the id of the mail queue entry created upon receipt
43             #pod env_to - the recipient of the message (an email addr)
44             #pod time - the timestamp on the header
45             #pod
46             #pod At present, these are all required. In the future they may have more flexible
47             #pod semantics, and more formats for output of hops may be supported.
48             #pod
49             #pod =cut
50              
51             sub trace_headers {
52 1     1 1 3 my ($self, $arg) = @_;
53              
54 1 50       11 Carp::confess("no hops provided") unless $arg->{hops};
55              
56 1         2 my @received;
57             my %last;
58 1         2 for my $hop (@{ $arg->{hops} }) {
  1         7  
59 3         13 my %hop = (%$hop);
60              
61 3         9 for my $key (keys %hop) {
62 20 100       37 if (ref $hop->{$key} eq 'CODE') {
63 3         7 $hop{ $key } = $hop{$key}->(\%last);
64             }
65             }
66              
67             my $env_to = ref $hop{env_to} ? $hop{env_to}
68 3 100       11 : $hop{env_to} ? [ $hop{env_to} ]
    100          
69             : [ ];
70              
71 3 100       9 my $fmt = @$env_to == 1 ? $POSTFIX_FMT{for} : $POSTFIX_FMT{nofor};
72              
73             push @received, sprintf $fmt,
74             $hop{from_helo},
75             $hop{from_rdns},
76             $hop{from_ip},
77             $hop{by_name}, # by_ip someday?
78             $hop{queue_id},
79             @$env_to == 1 ? $env_to->[0] : '',
80 3 100       11 (Email::Date::Format::email_gmdate($hop{time}) . ' (GMT)');
81              
82 3         85 %last = %hop;
83             }
84              
85 1         5 return [ reverse @received ];
86             }
87              
88             #pod =head2 create_email
89             #pod
90             #pod my $email_simple = Email::Simple::Test::TraceHeaders->create_email(
91             #pod \%trace_arg
92             #pod );
93             #pod
94             #pod This creates and returns an Email::Simple message with trace headers created by
95             #pod C>.
96             #pod
97             #pod =cut
98              
99             sub create_email {
100 1     1 1 4 my ($self, $arg) = @_;
101              
102             my $email = Email::Simple->create(
103             header => [
104 1         2 (map {; Received => $_ } @{ $self->trace_headers($arg) }),
  3         13  
  1         3  
105              
106             From => '"X. Ample" ',
107             To => '"E. Xampe" ',
108             ],
109             body => "This is a test message.\n",
110             );
111              
112 1         763 return $email;
113             }
114              
115             #pod =head1 HELPERS
116             #pod
117             #pod Some routines can be exported to make it easier to set up trace headers.
118             #pod
119             #pod You can get them all with:
120             #pod
121             #pod use Email::Simple::Test::TraceHeaders -helpers;
122             #pod
123             #pod =head2 prev
124             #pod
125             #pod This helper gets a value from the previous hop. So, given these hops:
126             #pod
127             #pod { ..., by_name => 'mx.example.com', ... },
128             #pod { ..., from_rdns => prev('by_name'), ... },
129             #pod
130             #pod ...the second hop will have F as its C parameter.
131             #pod
132             #pod =cut
133              
134             sub _build_prev {
135 1     1   168 my ($self) = @_;
136              
137             sub {
138 3     3   90 my ($name) = @_;
139              
140             sub {
141 3     3   4 my ($last) = @_;
142 3         7 $last->{ $name };
143             }
144 3         24 }
145 1         4 }
146              
147             1;
148              
149             __END__