1package Sisimai::Lhost::Yahoo; 2use parent 'Sisimai::Lhost'; 3use feature ':5.10'; 4use strict; 5use warnings; 6 7sub description { 'Yahoo! MAIL: https://www.yahoo.com' } 8sub make { 9 # Detect an error from Yahoo! MAIL 10 # @param [Hash] mhead Message headers of a bounce email 11 # @param [String] mbody Message body of a bounce email 12 # @return [Hash] Bounce data list and message/rfc822 part 13 # @return [Undef] failed to parse or the arguments are missing 14 # @since v4.1.3 15 my $class = shift; 16 my $mhead = shift // return undef; 17 my $mbody = shift // return undef; 18 19 # X-YMailISG: YtyUVyYWLDsbDh... 20 # X-YMail-JAS: Pb65aU4VM1mei... 21 # X-YMail-OSG: bTIbpDEVM1lHz... 22 # X-Originating-IP: [192.0.2.9] 23 return undef unless $mhead->{'x-ymailisg'}; 24 25 state $indicators = __PACKAGE__->INDICATORS; 26 state $rebackbone = qr|^--- Below this line is a copy of the message[.]|m; 27 state $startingof = { 'message' => ['Sorry, we were unable to deliver your message'] }; 28 29 my $dscontents = [__PACKAGE__->DELIVERYSTATUS]; 30 my $emailsteak = Sisimai::RFC5322->fillet($mbody, $rebackbone); 31 my $readcursor = 0; # (Integer) Points the current cursor position 32 my $recipients = 0; # (Integer) The number of 'Final-Recipient' header 33 my $v = undef; 34 35 for my $e ( split("\n", $emailsteak->[0]) ) { 36 # Read error messages and delivery status lines from the head of the email 37 # to the previous line of the beginning of the original message. 38 unless( $readcursor ) { 39 # Beginning of the bounce message or message/delivery-status part 40 $readcursor |= $indicators->{'deliverystatus'} if index($e, $startingof->{'message'}->[0]) == 0; 41 next; 42 } 43 next unless $readcursor & $indicators->{'deliverystatus'}; 44 next unless length $e; 45 46 # Sorry, we were unable to deliver your message to the following address. 47 # 48 # <kijitora@example.org>: 49 # Remote host said: 550 5.1.1 <kijitora@example.org>... User Unknown [RCPT_TO] 50 $v = $dscontents->[-1]; 51 52 if( $e =~ /\A[<](.+[@].+)[>]:[ \t]*\z/ ) { 53 # <kijitora@example.org>: 54 if( $v->{'recipient'} ) { 55 # There are multiple recipient addresses in the message body. 56 push @$dscontents, __PACKAGE__->DELIVERYSTATUS; 57 $v = $dscontents->[-1]; 58 } 59 $v->{'recipient'} = $1; 60 $recipients++; 61 62 } else { 63 if( index($e, 'Remote host said:') == 0 ) { 64 # Remote host said: 550 5.1.1 <kijitora@example.org>... User Unknown [RCPT_TO] 65 $v->{'diagnosis'} = $e; 66 67 # Get SMTP command from the value of "Remote host said:" 68 $v->{'command'} = $1 if $e =~ /\[([A-Z]{4}).*\]\z/; 69 } else { 70 # <mailboxfull@example.jp>: 71 # Remote host said: 72 # 550 5.2.2 <mailboxfull@example.jp>... Mailbox Full 73 # [RCPT_TO] 74 if( $v->{'diagnosis'} eq 'Remote host said:' ) { 75 # Remote host said: 76 # 550 5.2.2 <mailboxfull@example.jp>... Mailbox Full 77 if( $e =~ /\[([A-Z]{4}).*\]\z/ ) { 78 # [RCPT_TO] 79 $v->{'command'} = $1; 80 81 } else { 82 # 550 5.2.2 <mailboxfull@example.jp>... Mailbox Full 83 $v->{'diagnosis'} = $e; 84 } 85 } else { 86 # Error message which does not start with 'Remote host said:' 87 $v->{'diagnosis'} .= ' '.$e; 88 } 89 } 90 } 91 } 92 return undef unless $recipients; 93 94 for my $e ( @$dscontents ) { 95 $e->{'diagnosis'} =~ y/\n/ /; 96 $e->{'diagnosis'} = Sisimai::String->sweep($e->{'diagnosis'}); 97 $e->{'command'} ||= 'RCPT' if $e->{'diagnosis'} =~ /[<].+[@].+[>]/; 98 } 99 return { 'ds' => $dscontents, 'rfc822' => $emailsteak->[1] }; 100} 101 1021; 103__END__ 104 105=encoding utf-8 106 107=head1 NAME 108 109Sisimai::Lhost::Yahoo - bounce mail parser class for C<Yahoo! MAIL>. 110 111=head1 SYNOPSIS 112 113 use Sisimai::Lhost::Yahoo; 114 115=head1 DESCRIPTION 116 117Sisimai::Lhost::Yahoo parses a bounce email which created by C<Yahoo! MAIL>. 118Methods in the module are called from only Sisimai::Message. 119 120=head1 CLASS METHODS 121 122=head2 C<B<description()>> 123 124C<description()> returns description string of this module. 125 126 print Sisimai::Lhost::Yahoo->description; 127 128=head2 C<B<make(I<header data>, I<reference to body string>)>> 129 130C<make()> method parses a bounced email and return results as a array reference. 131See Sisimai::Message for more details. 132 133=head1 AUTHOR 134 135azumakuniyuki 136 137=head1 COPYRIGHT 138 139Copyright (C) 2014-2020 azumakuniyuki, All rights reserved. 140 141=head1 LICENSE 142 143This software is distributed under The BSD 2-Clause License. 144 145=cut 146 147