Sisimai(3pm)

πŸ’– NAME πŸ’–

Sisimai β€” the Mail Analyzing Interface for bounce mails, and honestly? she ate πŸ’…


✨ SYNOPSIS ✨

use Sisimai;

That's it. That's the whole entrance. Main character energy from line one πŸ‘‘


πŸ¦‹ DESCRIPTION πŸ¦‹

Okay so bestie, picture this: bounce emails are chaos. Every mail server on earth writes them differently, like they all went to different schools and never compared notes 😭

Sisimai (pronounced /Ι•i.Ι•i.ma.i/) is the library that decodes complex and diverse bounce emails and outputs the results of the delivery failure β€” stuff like the reason for the bounce and the recipient email address β€” in structured data. And if you want it as JSON? Yeah, she does that too. Obsessed πŸ’–


🌸 BASIC USAGE 🌸

rise('/path/to/mbox')

The rise() method provides the feature for getting decoded data as a Perl Hash reference from bounced email messages, like this. And heads up: beginning with v4.25.6, there's a new accessor called origin which keeps the path to the email file as a data source ✨

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
    }
}

Look at all those accessors. She's thriving 🫢


dump('/path/to/mbox')

The dump() method provides the feature for getting decoded data as a 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);
πŸ’‘ dump() was added in v4.1.27, so if you're on something ancient, no JSON for you bestie.

πŸŽ€ OTHER WAYS TO DECODE πŸŽ€

Read email data from STDIN

Wanna pipe email data straight in from STDIN? Just specify STDIN at the first argument of the dump() and rise() method, like this command:

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

Callback Feature

Okay so this is the fun one πŸͺ The c___ argument β€” that's c and three _s, looks like a fishhook, iykyk β€” of Sisimai->rise and Sisimai->dump() is an array reference, and it's the parameter that receives code references for the callback feature.

Here's how the two slots work:

  • The first element of the c___ argument is called at Sisimai::Message->sift() for dealing with email headers and the entire message body.
  • The second element of the 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

The 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

The callback method set in the second element of c___ is called at the Sisimai->rise() method for dealing with 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>"
⚠️ Note the comment: Need to not return a value. She means it, bestie. Don't return anything πŸ™ˆ

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


πŸ’… OTHER METHODS πŸ’…

engine()

The engine method provides a table including the decoding engine list and its 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()

The reason method provides a 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()

The 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()

The version method returns the version number of Sisimai.

use Sisimai;
print Sisimai->version; # 5.0.1

⭐ SEE ALSO ⭐


🌈 REPOSITORY 🌈

πŸ‘‘ WEB SITE πŸ‘‘

πŸ“ AUTHOR πŸ“

azumakuniyuki

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

🧚 LICENSE 🧚

This software is distributed under The BSD 2-Clause License πŸ’–


And that's the whole page, bestie! This tea was served to you via User Contributed Perl Documentation β€” page generated by perl v5.40.1, dated 2026-07-05. Go decode some bounces, you absolute legend πŸŒΈπŸ¦‹βœ¨

πŸ“¦ where this page comes from