NAME

Sisimai - Mail Analyzing Interface for bounce mails.

SYNOPSIS

use Sisimai;

DESCRIPTION

Sisimai 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.

BASIC USAGE

rise('/path/to/mbox')

rise() 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.

use Sisimai;
my $v = Sisimai->rise('/path/to/mbox'); # 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 = '';
my $f = IO::File->new('/path/to/mbox'); # or path to Maildir/
{ local $/ = undef; $r = <$f>; $f->close }
my $v = Sisimai->rise(\$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('/path/to/mbox', 'delivered' => 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('/path/to/mbox', 'vacation' => 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('json');       # Convert to JSON string
        print $e->dump('json');         # JSON formatted bounce data
    }
}

dump('/path/to/mbox')

dump() method provides the feature for getting decoded data as JSON string from bounced email messages like the following code:

use Sisimai;

# Get JSON string from path of a mailbox or a Maildir/
my $j = Sisimai->dump('/path/to/mbox'); # 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('/path/to/mbox', 'delivered' => 1, 'vacation' => 1);

OTHER WAYS TO DECODE

Read email data from STDIN

If you want to pass email data from STDIN, specify STDIN at the first argument of dump() and rise() method like following command:

% cat ./path/to/bounce.eml | perl -MSisimai -lE 'print Sisimai->dump(STDIN)'

Callback Feature

c___ (c and three _s, looks like a fishhook) argument of Sisimai->rise and Sisimai-dump()> is an array reference and is a parameter to receive code references for callback feature. The first element of c___ argument is called at Sisimai::Message-sift()> for dealing email headers and entire message body. The second element of c___ argument is called at the end of each email file processing. The result generated by the callback method is accessible via Sisimai::Fact-catch>.

[0] For email headers and the body

Callback method set in the first element of c___ is called at Sisimai::Message-sift()>.

use Sisimai;
my $code = sub {
    my $args = shift;               # (*Hash)
    my $head = $args->{'headers'};  # (*Hash)  Email headers
    my $body = $args->{'message'};  # (String) Message body
    my $adds = { 'x-mailer' => '', 'queue-id' => '' };

    if( $body =~ m/^X-Postfix-Queue-ID:\s*(.+)$/m ) {
        $adds->{'queue-id'} = $1;
    }

    $adds->{'x-mailer'} = $head->{'x-mailer'} || '';
    return $adds;
};
my $data = Sisimai->rise('/path/to/mbox', 'c___' => [$code, undef]);
my $json = Sisimai->dump('/path/to/mbox', 'c___' => [$code, undef]);

print $data->[0]->catch->{'x-mailer'};    # "Apple Mail (2.1283)"
print $data->[0]->catch->{'queue-id'};    # "43f4KX6WR7z1xcMG"

[1] For each email file

Callback method set in the second element of c___ is called at Sisimai-rise()> method for dealing each email file.

my $path = '/path/to/maildir';
my $code = sub {
    my $args = shift;           # (*Hash)
    my $kind = $args->{'kind'}; # (String)  Sisimai::Mail->kind
    my $mail = $args->{'mail'}; # (*String) Entire email message
    my $path = $args->{'path'}; # (String)  Sisimai::Mail->path
    my $fact = $args->{'fact'}; # (*Array)  List of Sisimai::Fact

    for my $e ( @$fact ) {
        # Store custom information in the "catch" accessor.
        $e->{'catch'} ||= {};
        $e->{'catch'}->{'size'} = length $$mail;
        $e->{'catch'}->{'kind'} = ucfirst $kind;

        if( $$mail =~ /^Return-Path: (.+)$/m ) {
            # Return-Path: <MAILER-DAEMON>
            $e->{'catch'}->{'return-path'} = $1;
        }

        # Save the original email with an additional "X-Sisimai-Decoded:" header to a different PATH.
        my $a = sprintf("X-Sisimai-Decoded: %d\n", scalar @$fact);
        my $p = sprintf("/path/to/another/directory/sisimai-%s.eml", $e->token);
        my $f = IO::File->new($p, 'w');
        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 'maildir';

    # Need to not return a value
};

my $list = Sisimai->rise($path, 'c___' => [undef, $code]);
print $list->[0]->{'catch'}->{'size'};          # 2202
print $list->[0]->{'catch'}->{'kind'};          # "Maildir"
print $list->[0]->{'catch'}->{'return-path'};   # "<MAILER-DAEMON>"

More information about the callback feature is available at https://libsisimai.org/en/usage/#callback

OTHER METHODS

engine()

engine method provides table including decoding engine list and it's description.

use Sisimai;
my $v = Sisimai->engine();
for my $e ( keys %$v ) {
    print $e;           # Sisimai::MTA::Sendmail
    print $v->{ $e };   # V8Sendmail: /usr/sbin/sendmail
}

reason()

reason method provides table including all the reasons Sisimai can detect

use Sisimai;
my $v = Sisimai->reason();
for my $e ( keys %$v ) {
    print $e;           # Blocked
    print $v->{ $e };   # 'Email rejected due to client IP address or a hostname'
}

match()

match method receives an error message as a string and returns a reason name like the following:

use Sisimai;
my $v = '550 5.1.1 User unknown';
my $r = Sisimai->match($v);
print $r;   # "userunknown"

version()

version method returns the version number of Sisimai.

use Sisimai;
print Sisimai->version; # 5.0.1

SEE ALSO

Sisimai::Mail - Mailbox or Maildir object
Sisimai::Fact - Decoded data object
https://libsisimai.org/ - Sisimai - Mail Analyzing Interface Library
https://tools.ietf.org/html/rfc3463 - RFC3463: Enhanced Mail System Status Codes
https://tools.ietf.org/html/rfc3464 - RFC3464: An Extensible Message Format for Delivery Status Notifications
https://tools.ietf.org/html/rfc5321 - RFC5321: Simple Mail Transfer Protocol
https://tools.ietf.org/html/rfc5322 - RFC5322: Internet Message Format

REPOSITORY

https://github.com/sisimai/p5-sisimai - Sisimai on GitHub

WEB SITE

https://libsisimai.org/ - Mail Analyzing Interface Library

https://github.com/sisimai/rb-sisimai - Ruby version of Sisimai

AUTHOR

azumakuniyuki

COPYRIGHT

Copyright (C) 2014-2024 azumakuniyuki, All rights reserved.

LICENSE

This software is distributed under The BSD 2-Clause License.