File Coverage

blib/lib/Mail/Qmail/Filter/SkipQueue.pm
Criterion Covered Total %
statement 8 41 19.5
branch 0 22 0.0
condition 0 9 0.0
subroutine 3 5 60.0
pod 1 1 100.0
total 12 78 15.3


line stmt bran cond sub pod time code
1 1     1   982 use 5.014;
  1         3  
2 1     1   5 use warnings;
  1         2  
  1         47  
3              
4             package Mail::Qmail::Filter::SkipQueue;
5              
6             our $VERSION = '1.01';
7              
8 1     1   5 use Mo qw(coerce);
  1         2  
  1         13  
9             extends 'Mail::Qmail::Filter';
10              
11             sub filter {
12 0     0 1   my $self = shift;
13 0           my $message = $self->message;
14              
15 0 0 0       require Qmail::Deliverable and Qmail::Deliverable->import('dot_qmail')
16             unless defined &dot_qmail;
17              
18 0           my $dot_qmail;
19 0           for ( $message->to ) {
20 0 0         my $_dot_qmail = dot_qmail($_)
21             or return $self->debug( 'No .qmail file found for rcpt' => $_ );
22 0           $self->debug( 'using file' => $_dot_qmail );
23 0 0 0       return $self->debug('Delivery to different .qmail files not supported')
24             if defined $dot_qmail && $_dot_qmail ne $dot_qmail;
25 0           $dot_qmail = $_dot_qmail;
26             }
27              
28 0 0         open my $fh, '<', $dot_qmail
29             or return $self->debug( "Cannot read $dot_qmail", $! );
30              
31 0           my @commands;
32 0           while ( defined( my $line = <$fh> ) ) {
33 0 0         next if /^#/;
34 0           chomp $line;
35 0 0         if ( $line !~ /^\|/ ) {
36 0           $self->debug( 'Delivery method not supported', $line );
37             }
38             else {
39 0           push @commands, $line;
40             }
41             }
42              
43 0           local $ENV{SENDER} = $message->from;
44 0           for (@commands) {
45 0 0 0       require Capture::Tiny and Capture::Tiny->import('capture_merged')
46             unless defined &capture_merged;
47             my ( $output, $exitcode ) = capture_merged(
48             sub {
49 0 0   0     open my $fh, $_ or return $self->debug( "Cannot start $_", $! );
50 0           print $fh $message->body;
51 0           close $fh;
52 0           $?;
53             }
54 0           );
55 0           $output = join '/', split /\n/, $output;
56 0           $exitcode >>= 8;
57 0           $self->debug( qq("$_" returned with exit code $exitcode) => $output );
58 0 0         next if $exitcode == 0;
59 0 0         last if $exitcode == 99;
60 0 0         $self->reject($output) if $exitcode == 100;
61 0           return;
62             }
63              
64 0           $self->debug( action => 'delivered' );
65             }
66              
67             1;
68              
69             __END__
70              
71             =head1 NAME
72              
73             Mail::Qmail::Filter::SkipQueue -
74             deliver message using external commands
75              
76             =head1 SYNOPSIS
77              
78             use Mail::Qmail::Filter;
79            
80             Mail::Qmail::Filter->new->add_filter(
81             '::SkipQueue',
82             )->run;
83              
84             =head1 DESCRIPTION
85              
86             This L<Mail::Qmail::Filter> plugin tries to find the appropriate C<.qmail> file
87             for all recipients and pipes the message to any command lines listed in those
88             files.
89             That is, it tries to deliver the message itself, circumventing C<qmail-local>.
90             The usual rules for exit codes from the programs called apply.
91             Other delivery methods, namely maildir or mbox lines, are not supported
92             and will be skipped.
93              
94             =head1 DISCLAIMER
95              
96             This plugin is considered experimental.
97             I implemented it as a proof-of-concept when developing
98             L<Mail::Qmail::Filter::CheckDeliverability>.
99             I do not recommend to use it a production environment.
100              
101             =head1 SEE ALSO
102              
103             L<Mail::Qmail::Filter/COMMON PARAMETERS FOR ALL FILTERS>,
104             L<Mail::Qmail::Filter::CheckDeliverability>
105              
106             =head1 LICENSE AND COPYRIGHT
107              
108             Copyright 2019 Martin Sluka.
109              
110             This module is free software; you can redistribute it and/or modify it
111             under the terms of the the Artistic License (2.0). You may obtain a
112             copy of the full license at:
113              
114             L<http://www.perlfoundation.org/artistic_license_2_0>
115              
116             Any use, modification, and distribution of the Standard or Modified
117             Versions is governed by this Artistic License. By using, modifying or
118             distributing the Package, you accept this license. Do not use, modify,
119             or distribute the Package, if you do not accept this license.
120              
121             If your Modified Version has been derived from a Modified Version made
122             by someone other than you, you are nevertheless required to ensure that
123             your Modified Version complies with the requirements of this license.
124              
125             This license does not grant you the right to use any trademark, service
126             mark, tradename, or logo of the Copyright Holder.
127              
128             This license includes the non-exclusive, worldwide, free-of-charge
129             patent license to make, have made, use, offer to sell, sell, import and
130             otherwise transfer the Package with respect to any patent claims
131             licensable by the Copyright Holder that are necessarily infringed by the
132             Package. If you institute patent litigation (including a cross-claim or
133             counterclaim) against any party alleging that the Package constitutes
134             direct or contributory patent infringement, then this Artistic License
135             to you shall terminate on the date that such litigation is filed.
136              
137             Disclaimer of Warranty: THE PACKAGE IS PROVIDED BY THE COPYRIGHT HOLDER
138             AND CONTRIBUTORS "AS IS' AND WITHOUT ANY EXPRESS OR IMPLIED WARRANTIES.
139             THE IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
140             PURPOSE, OR NON-INFRINGEMENT ARE DISCLAIMED TO THE EXTENT PERMITTED BY
141             YOUR LOCAL LAW. UNLESS REQUIRED BY LAW, NO COPYRIGHT HOLDER OR
142             CONTRIBUTOR WILL BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, OR
143             CONSEQUENTIAL DAMAGES ARISING IN ANY WAY OUT OF THE USE OF THE PACKAGE,
144             EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
145              
146             =cut