.\" -*- mode: troff; coding: utf-8 -*- .\" Automatically generated by Pod::Man 5.01 (Pod::Simple 3.43) .\" .\" Standard preamble: .\" ======================================================================== .de Sp \" Vertical space (when we can't use .PP) .if t .sp .5v .if n .sp .. .de Vb \" Begin verbatim text .ft CW .nf .ne \\$1 .. .de Ve \" End verbatim text .ft R .fi .. .\" \*(C` and \*(C' are quotes in nroff, nothing in troff, for use with C<>. .ie n \{\ . ds C` "" . ds C' "" 'br\} .el\{\ . ds C` . ds C' 'br\} .\" .\" Escape single quotes in literal strings from groff's Unicode transform. .ie \n(.g .ds Aq \(aq .el .ds Aq ' .\" .\" If the F register is >0, we'll generate index entries on stderr for .\" titles (.TH), headers (.SH), subsections (.SS), items (.Ip), and index .\" entries marked with X<> in POD. Of course, you'll have to process the .\" output yourself in some meaningful fashion. .\" .\" Avoid warning from groff about undefined register 'F'. .de IX .. .nr rF 0 .if \n(.g .if rF .nr rF 1 .if (\n(rF:(\n(.g==0)) \{\ . if \nF \{\ . de IX . tm Index:\\$1\t\\n%\t"\\$2" .. . if !\nF==2 \{\ . nr % 0 . nr F 2 . \} . \} .\} .rr rF .\" ======================================================================== .\" .IX Title "Sisimai 3pm" .TH Sisimai 3pm 2024-03-16 "perl v5.38.2" "User Contributed Perl Documentation" .\" For nroff, turn off justification. Always turn off hyphenation; it makes .\" way too many mistakes in technical documents. .if n .ad l .nh .SH NAME Sisimai \- Mail Analyzing Interface for bounce mails. .SH SYNOPSIS .IX Header "SYNOPSIS" .Vb 1 \& use Sisimai; .Ve .SH DESCRIPTION .IX Header "DESCRIPTION" \&\f(CW\*(C`Sisimai\*(C'\fR is a library that decodes complex and diverse bounce emails and outputs the results of the delivery failure, such as the reason for the bounce and the recipient email address, in structured data. It is also possible to output in JSON format. .SH "BASIC USAGE" .IX Header "BASIC USAGE" .ie n .SS """\fBrise(\*(Aq/path/to/mbox\*(Aq)\fP""" .el .SS \f(CW\fP\f(CBrise(\*(Aq/path/to/mbox\*(Aq)\fP\f(CW\fP .IX Subsection "rise(/path/to/mbox)" \&\f(CWrise()\fR method provides the feature for getting decoded data as Perl Hash reference from bounced email messages as the following. Beginning with v4.25.6, new accessor origin which keeps the path to email file as a data source is available. .PP .Vb 2 \& use Sisimai; \& my $v = Sisimai\->rise(\*(Aq/path/to/mbox\*(Aq); # or path to Maildir/ \& \& # In v4.23.0, the rise() and dump() methods of the Sisimai class can now read the entire bounce \& # email as a string, in addition to the PATH to the email file or mailbox. \& use IO::File; \& my $r = \*(Aq\*(Aq; \& my $f = IO::File\->new(\*(Aq/path/to/mbox\*(Aq); # or path to Maildir/ \& { local $/ = undef; $r = <$f>; $f\->close } \& my $v = Sisimai\->rise(\e$r); \& \& # If you also need analysis results that are "delivered" (successfully delivered), please \& # specify the "delivered" option to the rise() method as shown below. \& my $v = Sisimai\->rise(\*(Aq/path/to/mbox\*(Aq, \*(Aqdelivered\*(Aq => 1); \& \& # From v5.0.0, Sisimai no longer returns analysis results with a bounce reason of "vacation" by \& # default. If you also need analysis results that show a "vacation" reason, please specify the \& # "vacation" option to the rise() method as shown in the following code. \& my $v = Sisimai\->rise(\*(Aq/path/to/mbox\*(Aq, \*(Aqvacation\*(Aq => 1); \& \& if( defined $v ) { \& for my $e ( @$v ) { \& print ref $e; # Sisimai::Fact \& print ref $e\->recipient; # Sisimai::Address \& print ref $e\->timestamp; # Sisimai::Time \& \& print $e\->addresser\->address; # "michitsuna@example.org" # From \& print $e\->recipient\->address; # "kijitora@example.jp" # To \& print $e\->recipient\->host; # "example.jp" \& print $e\->deliverystatus; # "5.1.1" \& print $e\->replycode; # "550" \& print $e\->reason; # "userunknown" \& print $e\->origin; # "/var/spool/bounce/new/1740074341.eml" \& print $e\->hardbounce; # 1 \& \& my $h = $e\->damn(); # Convert to HASH reference \& my $j = $e\->dump(\*(Aqjson\*(Aq); # Convert to JSON string \& print $e\->dump(\*(Aqjson\*(Aq); # JSON formatted bounce data \& } \& } .Ve .ie n .SS """\fBdump(\*(Aq/path/to/mbox\*(Aq)\fP""" .el .SS \f(CW\fP\f(CBdump(\*(Aq/path/to/mbox\*(Aq)\fP\f(CW\fP .IX Subsection "dump(/path/to/mbox)" \&\f(CWdump()\fR method provides the feature for getting decoded data as JSON string from bounced email messages like the following code: .PP .Vb 1 \& use Sisimai; \& \& # Get JSON string from path of a mailbox or a Maildir/ \& my $j = Sisimai\->dump(\*(Aq/path/to/mbox\*(Aq); # or path to Maildir/ \& # dump() is added in v4.1.27 \& print $j; # decoded data as JSON \& \& # dump() method also accepts "delivered" and "vacation" option like the following code: \& my $j = Sisimai\->dump(\*(Aq/path/to/mbox\*(Aq, \*(Aqdelivered\*(Aq => 1, \*(Aqvacation\*(Aq => 1); .Ve .SH "OTHER WAYS TO PARSE" .IX Header "OTHER WAYS TO PARSE" .SS "Read email data from STDIN" .IX Subsection "Read email data from STDIN" If you want to pass email data from STDIN, specify \fBSTDIN\fR at the first argument of \f(CWdump()\fR and \&\f(CWrise()\fR method like following command: .PP .Vb 1 \& % cat ./path/to/bounce.eml | perl \-MSisimai \-lE \*(Aqprint Sisimai\->dump(STDIN)\*(Aq .Ve .SS "Callback Feature" .IX Subsection "Callback Feature" \&\f(CW\*(C`c_\|_\|_\*(C'\fR (c and three _s, looks like a fishhook) argument of Sisimai\->rise and \f(CW\*(C`Sisimai\-\*(C'\fR\fBdump()\fR> is an array reference and is a parameter to receive code references for callback feature. The first element of \f(CW\*(C`c_\|_\|_\*(C'\fR argument is called at \f(CW\*(C`Sisimai::Message\-\*(C'\fR\fBsift()\fR> for dealing email headers and entire message body. The second element of \f(CW\*(C`c_\|_\|_\*(C'\fR argument is called at the end of each email file processing. The result generated by the callback method is accessible via \f(CW\*(C`Sisimai::Fact\-\*(C'\fRcatch>. .PP \fI[0] For email headers and the body\fR .IX Subsection "[0] For email headers and the body" .PP Callback method set in the first element of \f(CW\*(C`c_\|_\|_\*(C'\fR is called at \f(CW\*(C`Sisimai::Message\-\*(C'\fR\fBsift()\fR>. .PP .Vb 6 \& use Sisimai; \& my $code = sub { \& my $args = shift; # (*Hash) \& my $head = $args\->{\*(Aqheaders\*(Aq}; # (*Hash) Email headers \& my $body = $args\->{\*(Aqmessage\*(Aq}; # (String) Message body \& my $adds = { \*(Aqx\-mailer\*(Aq => \*(Aq\*(Aq, \*(Aqqueue\-id\*(Aq => \*(Aq\*(Aq }; \& \& if( $body =~ m/^X\-Postfix\-Queue\-ID:\es*(.+)$/m ) { \& $adds\->{\*(Aqqueue\-id\*(Aq} = $1; \& } \& \& $adds\->{\*(Aqx\-mailer\*(Aq} = $head\->{\*(Aqx\-mailer\*(Aq} || \*(Aq\*(Aq; \& return $adds; \& }; \& my $data = Sisimai\->rise(\*(Aq/path/to/mbox\*(Aq, \*(Aqc_\|_\|_\*(Aq => [$code, undef]); \& my $json = Sisimai\->dump(\*(Aq/path/to/mbox\*(Aq, \*(Aqc_\|_\|_\*(Aq => [$code, undef]); \& \& print $data\->[0]\->catch\->{\*(Aqx\-mailer\*(Aq}; # "Apple Mail (2.1283)" \& print $data\->[0]\->catch\->{\*(Aqqueue\-id\*(Aq}; # "43f4KX6WR7z1xcMG" .Ve .PP \fI[1] For each email file\fR .IX Subsection "[1] For each email file" .PP Callback method set in the second element of \f(CW\*(C`c_\|_\|_\*(C'\fR is called at \f(CW\*(C`Sisimai\-\*(C'\fR\fBrise()\fR> method for dealing each email file. .PP .Vb 7 \& my $path = \*(Aq/path/to/maildir\*(Aq; \& my $code = sub { \& my $args = shift; # (*Hash) \& my $kind = $args\->{\*(Aqkind\*(Aq}; # (String) Sisimai::Mail\->kind \& my $mail = $args\->{\*(Aqmail\*(Aq}; # (*String) Entire email message \& my $path = $args\->{\*(Aqpath\*(Aq}; # (String) Sisimai::Mail\->path \& my $fact = $args\->{\*(Aqfact\*(Aq}; # (*Array) List of Sisimai::Fact \& \& for my $e ( @$fact ) { \& # Store custom information in the "catch" accessor. \& $e\->{\*(Aqcatch\*(Aq} ||= {}; \& $e\->{\*(Aqcatch\*(Aq}\->{\*(Aqsize\*(Aq} = length $$mail; \& $e\->{\*(Aqcatch\*(Aq}\->{\*(Aqkind\*(Aq} = ucfirst $kind; \& \& if( $$mail =~ /^Return\-Path: (.+)$/m ) { \& # Return\-Path: \& $e\->{\*(Aqcatch\*(Aq}\->{\*(Aqreturn\-path\*(Aq} = $1; \& } \& \& # Save the original email with an additional "X\-Sisimai\-Parsed:" header to a different PATH. \& my $a = sprintf("X\-Sisimai\-Parsed: %d\en", scalar @$fact); \& my $p = sprintf("/path/to/another/directory/sisimai\-%s.eml", $e\->token); \& my $f = IO::File\->new($p, \*(Aqw\*(Aq); \& my $v = $$mail; $v =~ s/^(From:.+)$/$a$1/m; \& print $f $v; $f\->close; \& } \& \& # Remove the email file in Maildir/ after decoding \& unlink $path if $kind eq \*(Aqmaildir\*(Aq; \& \& # Need to not return a value \& }; \& \& my $list = Sisimai\->rise($path, \*(Aqc_\|_\|_\*(Aq => [undef, $code]); \& print $list\->[0]\->{\*(Aqcatch\*(Aq}\->{\*(Aqsize\*(Aq}; # 2202 \& print $list\->[0]\->{\*(Aqcatch\*(Aq}\->{\*(Aqkind\*(Aq}; # "Maildir" \& print $list\->[0]\->{\*(Aqcatch\*(Aq}\->{\*(Aqreturn\-path\*(Aq}; # "" .Ve .PP More information about the callback feature is available at .SH "OTHER METHODS" .IX Header "OTHER METHODS" .ie n .SS """\fBengine()\fP""" .el .SS \f(CW\fP\f(CBengine()\fP\f(CW\fP .IX Subsection "engine()" \&\f(CW\*(C`engine\*(C'\fR method provides table including decoding engine list and it's description. .PP .Vb 6 \& use Sisimai; \& my $v = Sisimai\->engine(); \& for my $e ( keys %$v ) { \& print $e; # Sisimai::MTA::Sendmail \& print $v\->{ $e }; # V8Sendmail: /usr/sbin/sendmail \& } .Ve .ie n .SS """\fBreason()\fP""" .el .SS \f(CW\fP\f(CBreason()\fP\f(CW\fP .IX Subsection "reason()" \&\f(CW\*(C`reason\*(C'\fR method provides table including all the reasons Sisimai can detect .PP .Vb 6 \& use Sisimai; \& my $v = Sisimai\->reason(); \& for my $e ( keys %$v ) { \& print $e; # Blocked \& print $v\->{ $e }; # \*(AqEmail rejected due to client IP address or a hostname\*(Aq \& } .Ve .ie n .SS """\fBmatch()\fP""" .el .SS \f(CW\fP\f(CBmatch()\fP\f(CW\fP .IX Subsection "match()" \&\f(CW\*(C`match\*(C'\fR method receives an error message as a string and returns a reason name like the following: .PP .Vb 4 \& use Sisimai; \& my $v = \*(Aq550 5.1.1 User unknown\*(Aq; \& my $r = Sisimai\->match($v); \& print $r; # "userunknown" .Ve .ie n .SS """\fBversion()\fP""" .el .SS \f(CW\fP\f(CBversion()\fP\f(CW\fP .IX Subsection "version()" \&\f(CW\*(C`version\*(C'\fR method returns the version number of Sisimai. .PP .Vb 2 \& use Sisimai; \& print Sisimai\->version; # 5.0.1 .Ve .SH "SEE ALSO" .IX Header "SEE ALSO" .IP "Sisimai::Mail \- Mailbox or Maildir object" 4 .IX Item "Sisimai::Mail - Mailbox or Maildir object" .PD 0 .IP "Sisimai::Fact \- Decoded data object" 4 .IX Item "Sisimai::Fact - Decoded data object" .IP " \- Sisimai — Mail Analyzing Interface Library" 4 .IX Item " - Sisimai — Mail Analyzing Interface Library" .IP " \- RFC3463: Enhanced Mail System Status Codes" 4 .IX Item " - RFC3463: Enhanced Mail System Status Codes" .IP " \- RFC3464: An Extensible Message Format for Delivery Status Notifications" 4 .IX Item " - RFC3464: An Extensible Message Format for Delivery Status Notifications" .IP " \- RFC5321: Simple Mail Transfer Protocol" 4 .IX Item " - RFC5321: Simple Mail Transfer Protocol" .IP " \- RFC5322: Internet Message Format" 4 .IX Item " - RFC5322: Internet Message Format" .PD .SH REPOSITORY .IX Header "REPOSITORY" \- Sisimai on GitHub .SH "WEB SITE" .IX Header "WEB SITE" \- Mail Analyzing Interface Library .PP \- Ruby version of Sisimai .SH AUTHOR .IX Header "AUTHOR" azumakuniyuki .SH COPYRIGHT .IX Header "COPYRIGHT" Copyright (C) 2014\-2024 azumakuniyuki, All rights reserved. .SH LICENSE .IX Header "LICENSE" This software is distributed under The BSD 2\-Clause License.