シシマイでの解析方法

基本的な使い方

メールの解析、構造化されたデータやJSON文字列の取得など、 シシマイが使える環境にバウンスメールを用意すれば直ぐに解析結果を得られる 最も簡単で基本的な使い方を紹介します。

Read

標準入力を読む

標準入力(STDIN)からバウンスメールのデータを読み込み、 シシマイで解析する方法の記述例です。 PerlやRubyのワンライナーでパイプラインを経由して 読み込む場合に便利な入力方法です。

Read

変数から読む

変数からバウンスメールのデータを読み込み シシマイで解析する方法の記述例です。バウンスメール をデータベースやジョブキューシステムから読み出して 解析する場合に便利な方法です。

Read

配信成功も含む

Sisimaiは既定の動作で配信できなかったメールだけを解析結果として 出力しますが、配信が成功したメール(配信通知)も解析結果に含める Sisimaiクラスのメソッド使用方法を紹介します。

Read

不在応答も含む

Sisimaiは既定の動作で配信できなかったメールだけを解析結果として 出力しますが、不在応答(Vacation)で返ってきたメールも解析結果に含める Sisimaiクラスのメソッド使用方法を紹介します。

Read

コールバック

コールバック機能を使うとシシマイが解析する前のデータ に対して、特定ヘッダの取得や部分的な書き換えなど、 独自の処理を行い、その結果を解析データに含めることができます。

Read

標準入力から読む


Sisimaiクラスの make()メソッドはSisimai 5.0.0で廃止になりました。 新たに実装されたrise()メソッドをかわりに使ってください。

Sisimai(シシマイ)のrise()dump()メソッドは、 引数にファイル名を指定する以外に、STDINを指定することによって、 標準入力(STDIN)からバウンスメールのデータを読み込むことができます。 この機能は初期のSisimaiから実装されていましたが、バグがあったため、 読み込みができない場合がありました。このバグはSisimai 4.18.1 (Perl版) (Ruby版) にて修正済みです。

Perl

STDINファイルハンドル(Perl)

Sisimaiクラスのdump()rise()メソッドは、第一引数にファイルハンドルSTDINを指定すると、 標準入力からバウンスメールのデータを読み込み、解析結果を返します。

% cat ./path/to/email | perl -MSisimai -lE 'print Sisimai->dump(STDIN)' | jq
[
  {
    "listid": "",
    "smtpagent": "Sendmail",
    ...
                
% cat ./path/to/email | perl -MSisimai -lE 'print $_->recipient->address for @{ Sisimai->rise(STDIN) }'
kijitora@example.jp
sironeko@example.org
                
Ruby

STDINオブジェクト(Ruby)

Ruby版Sisimaiも同様に、Sisimaiクラスの dump()rise()メソッドの 第一引数にSTDINオブジェクトを指定すると、 標準入力からバウンスメールのデータを読み込み、解析結果を返します。

% cat ./path/to/email | ruby -Ilib -rsisimai -e 'puts Sisimai.dump(STDIN)' | jq
[
  {
    "catch": "",
    "token": "d295b517a3ad6f8748031e1068e07ebd089c0277",
    ...
                
% cat ./path/to/email | ruby -rsisimai -e 'p Sisimai.rise(STDIN)'
[#<Sisimai::Data:0x007fa1b0993050 @addresser=#<Sisimai::Address:0x007fa1b0990e40 @user="kijitora", ...
                
Go

文字列"STDIN" (Go)

Go版Sisimaiも同様に、libsisimai.org/sisimaiパッケージの Rise()Dump()関数の 第一引数に文字列"STDIN"を指定すると、 標準入力からバウンスメールのデータを読み込み、解析結果を返します。

package main
import "fmt"
import "libsisimai.org/sisimai"

func main() {
    args := sisimai.Args()
    json, _ := sisimai.Dump("STDIN", args)
    if json != nil && *json != "" { fmt.Printf("%s\n", *json) }
}
                
% cat ./path/to/email | go run ./sisid.go | jq
[
  {
    "catch": "",
    "token": "d295b517a3ad6f8748031e1068e07ebd089c0277",
    ...
                

変数から読み込む

Sisimaiクラスの make()メソッドはSisimai 5.0.0で廃止になりました。 新たに実装されたrise()メソッドをかわりに使ってください。

Sisimaiクラスのrise()dump()の第一引数に変数 (Perlではスカラーリファレンス・RubyではStringオブジェクト・Goでは文字列) を指定することによって、ファイルとしてのメールや標準入力以外からバウンスメールのデータを読み込むことができます。

バウンスメールをデータベースやジョブキューシステムから読み出す場合に有用なこの機能 (Sisimai::Mail::Memory)はSisimai 4.23.0で実装されました。

Perl

Scalar Reference

rise()dump()の第一引数に スカラーリファレンスを指定すると、 Sisimai内部ではSisimai::Mail::Memoryが呼び出され、 メールのファイルや標準入力から読み込んだのと同様、解析結果が得られます。

#! /usr/bin/env perl
use Sisimai;
my $f = 'From MAILER-DAEMON Thu Dec 22 17:54:04 2015...';   # バウンスメール全体
my $v = Sisimai->rise(\$f);
for my $e ( @$v ) {
    print $e->action;           # "delayed"
    print $e->deliverystatus;   # "4.7.0"
    print $e->reason;           # "expired"
    print $e->diagnosticcode;   # "Envelope expired"
    print $e->hardbounce;       # 0
}
                
Ruby

String Object

Ruby版Sisimaiではrise()dump()の第一引数にStringオブジェクト を指定すると、Sisimai内部でSisimai::Mail::Memory が呼び出され、メールのファイルや標準入力から読み込んだのと同様、解析結果が得られます。

#! /usr/bin/env ruby
require 'sisimai'
f = 'From MAILER-DAEMON Thu Dec 22 17:54:04 2015...'    # バウンスメール全体
v = Sisimai.rise(f)
v.each do |e|
  puts e.action         # "delayed"
  puts e.deliverystatus # "4.7.0"
  puts e.reason         # "expired"
  puts e.diagnosticcode # "Envelope expired"
  puts e.hardbounce     # false
end
                
Go

文字列としてのメール内容

Rise()関数とDump()関数の第一引数に バウンスメール全体を含んだ文字列を指定すると、Sisimai内部では libisismai.org/sisimai/mail/memoryが呼び出され、 メールのファイルや標準入力から読み込んだのと同様に、解析結果が得られます。

package main
import "fmt"
import "libsisimai.org/sisimai"

func main() {
    mail := 'From MAILER-DAEMON Fri Feb  2 18:30:22 2018...'    // バウンスメール全体
    args := sisimai.Args()
    data, _ := sisimai.Rise(mail, args)
    if len(*data) > 0 { fmt.Printf("%s\n", data[0].Recipient.Address) }
}
                

配信成功も解析結果に含める

Sisimaiクラスの make()メソッドはSisimai 5.0.0で廃止になりました。 新たに実装されたrise()メソッドをかわりに使ってください。

Sisimaiクラスのrise()dump()は第二引数にdelivered を指定することによって、配信が成功した事を通知するメールも解析結果に含めることができます。

email

配信成功のサンプルメール

配送が成功したメールは github.com/sisimai/set-of-emails リポジトリの rfc3464-28.eml がサンプルとして用意してあります。 ここでは、このメールを解析するサンプルコードを紹介します。

Perl

delivered => 1

rise()dump()の第二引数に delivered => 1を指定すると、 配信に成功したメール(配信通知)も解析結果に含まれるようになります。 deliveredに偽となる値(0,undef,'') を指定した場合は、解析結果は生成されません。

#! /usr/bin/env perl
use Sisimai;
my $f = './set-of-emails/maildir/bsd/rfc3464-28.eml';
my $v = Sisimai->rise($f, 'delivered' => 1);
for my $e ( @$v ) {
    print $e->action;           # "delivered"
    print $e->deliverystatus;   # "2.1.5"
    print $e->reason;           # "delivered"
    print $e->diagnosticcode;   # "250 2.1.5 Ok"
    print $e->hardbounce;       # 0
}
                
Ruby

delivered: true

Perl版と同様に、Ruby版Sisimaiでもrise()dump()の第二引数にdelivered: trueを指定すると、 配信に成功したメール(配信通知)も解析結果に含まれるようになります。 deliveredに偽となる値(nil,false)を指定した場合は、 解析結果は生成されません。

#! /usr/bin/env ruby
require 'sisimai'
f = './set-of-emails/maildir/bsd/rfc3464-28.eml'
v = Sisimai.rise(f, delivered: true)
v.each do |e|
  puts e.action         # "delivered"
  puts e.deliverystatus # "2.1.5"
  puts e.reason         # "delivered"
  puts e.diagnosticcode # "250 2.1.5 Ok"
  puts e.hardbounce     # false
end
                
Go

args.Delivered = true

Perl版やRuby版と同様にGo版SisimaiでもRise()Dump()の第二引数に 指定する sis.DecodingArgs 構造体のDeliveredtrueを指定すると、配信に成功したメール(配信通知)も 解析結果に含まれるようになります。Deliveredの初期値は falseです。

package main
import "fmt"
import "libsisimai.org/sisimai"

func main() {
    path := "./set-of-emails/maildir/bsd/rfc3464-28.eml"
    args := sisimai.Args()
    args.Delivered = true

    sisi, _ := sisimai.Rise(path, args)
    if len(*sisi) > 0 { fmt.Printf("Recipient = %s\n", *sisi[0].Recipient.Address }
}
                

不在応答(Vacation)も解析結果に含める

Sisimaiクラスの make()メソッドはSisimai 5.0.0で廃止になりました。 新たに実装されたrise()メソッドをかわりに使ってください。

Sisimai 5.0.0でバウンス理由が vacationとなる バウンスメールはデフォルトで解析されなくなりました。必要な場合は vacationパラメーターをrise() メソッドに指定してください。

Sisimaiクラスのrise()dump()は第二引数にvacation を指定することによって、不在応答(Vacation)のメールも解析結果に含めることができます。

email

不在応答(Vacation)のサンプルメール

不在応答のメールは github.com/sisimai/set-of-emails リポジトリの rfc3834-01.eml がサンプルとして用意してあります。 ここでは、このメールを解析するサンプルコードを紹介します。

Perl

vacation => 1

rise()dump()の第二引数に vacation=> 1を指定すると、 不在応答のメールも解析結果に含まれるようになります。vacation に偽となる値(0,undef,'')を指定した場合は、解析結果は生成されません。

#! /usr/bin/env perl
use Sisimai;
my $f = './set-of-emails/maildir/bsd/rfc3834-01.eml';
my $v = Sisimai->rise($f, 'vacation' => 1);
for my $e ( @$v ) {
    print $e->action;           # ""
    print $e->deliverystatus;   # ""
    print $e->reason;           # "vacation"
    print $e->diagnosticcode;   # "I am currently away returning to the office on May 5th."
    print $e->hardbounce;       # 0
}
                
Ruby

vacation: true

Perl版と同様に、Ruby版Sisimaiでもrise()dump()の第二引数にvacation: trueを指定すると、 不在通知のメールも解析結果に含まれるようになります。vacation に偽となる値(nil,false)を指定した場合は、解析結果は生成されません。

#! /usr/bin/env ruby
require 'sisimai'
f = './set-of-emails/maildir/bsd/rfc3834-01.eml'
v = Sisimai.rise(f, vacation: true)
v.each do |e|
  puts e.action         # ""
  puts e.deliverystatus # ""
  puts e.reason         # "vacation"
  puts e.diagnosticcode # "I am currently away returning to the office on May 5th."
  puts e.hardbounce     # false
end
                
Go

args.Vacation = true

Perl版やRuby版と同様にGo版SisimaiでもRise()関数と Dump()関数の第二引数に指定する構造体 sis.DecodingArgs Vacationtrueを指定すると、 不在応答のメールも解析結果に含まれるようになります。 Vacationの初期値はfalseです。

package main
import "fmt"
import "libsisimai.org/sisimai"

func main() {
    path := "./set-of-emails/maildir/bsd/rfc3834-01.eml"
    args := sisimai.Args()
    args.Vacation = true

    sisi, _ := sisimai.Rise(path, args)
    if len(*sisi) > 0 { fmt.Printf("Recipient = %s\n", *sisi[0].Recipient.Address }
}
                

コールバック機能

Sisimaiクラスの make()メソッドはSisimai 5.0.0で廃止になりました。 新たに実装されたrise()メソッドをかわりに使ってください。

Sisimai 5.0.0でコールバック機能の仕様(引数の数・型)が変りました。 非互換の変更につき、Version 4でのコールバック機能は4-stable ブランチの GitHub/Callback Feature を確認してください。

Sisimai 4.19.0から実装されたコールバック機能を使用すると、 Sisimai::FactまたはSisimai::Messagecatch()メソッドを通して、バウンスメールを独自に処理した結果を取得することができます。 この機能はSisimaiが解析結果に含めない元メッセージ全体や 元メッセージの特定のヘッダの値(例えば配信IDなど)を取り出したりするのに便利です。

c___

c___に渡す引数(PerlとRuby)

Sisimaiクラスのrise()メソッドにおける c___ (c_が三つ、 釣り針に見える)に渡せる引数は、Perlのフックメソッド(サブルーチン)には配列リファレンス1つ、 RubyのフックメソッドにはArrayオブジェクト1つ です。引数の構造は以下のようになっています。

c___に渡す配列のインデックス 処理対象
[0] (下記コード例にある$code0) メールのヘッダーheadersおよび本文 message
[1] (下記コード例にある$code1) 元メールのファイルに対して
my $code0 = sub {
    my $args = shift;
    my $head = $args->{'headers'}; # ヘッダー
    my $body = $args->{'message'}; # 本文
};
my $code1 = sub {
    my $args = shift;
    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
};
my $list = Sisimai->rise('/path/to/mbox', 'c___' => [$code0, $code1]);
                
c___[0]

c___[0]の入力値

messageで得られる文字列はバウンスメールの本文です。 バウンスメールそのもののヘッダーは含まれていませんので、ハッシュ化された headersを参照してください。

キー名 データ型 説明
headers Hash バウンスメールのヘッダ部分(ハッシュ化済み)
message String ヘッダーは含まないバウンスメールのメール本文
c___[1]

c___[1]の入力値

mailで得られる文字列は、バウンスメールそのもの のヘッダーも含むバウンスメール全体です。


キー名 データ型 説明
kind String 元メールファイルの種類
mail *String ヘッダーも含むバウンスメール全体
path String 元メールファイルへのPATH
fact Array 解析結果であるSisimai::Factのリスト
Go

Callback0, Callback1に渡す引数(Go)

libsisimai.org/sisimaiパッケージのRise() 関数における sis.DecodingArgs 構造体のCallback0Callback1の引数と戻り値はそれぞれ以下のような構造になっています。

sis.DecodingArgs 引数 戻り値
Callback0 *sis.CallbackArg0

  • Headers map[string][]string
    • バウンスメールのヘッダー部分
  • Payload *string
    • ヘッダーを除くバウンスメールのメール本文
  • map[string]interface{}
  • error
Callback1 *sis.CallbackArg1

  • Path string 元メールのPath
  • Kind string 元メールの種類
    • "mailbox": UNIX mbox形式
    • "maildir": Maildir/形式
    • "memory": 変数からの読み込み
    • "stdin": STDINからの読み込み
  • Mail *string ヘッダーを含むバウンスメール全体
  • Fact *[]sis.Fact 解析済みデータ
  • bool
  • error
args := sisimai.Args()
args.Callback0 = func(arg *sisimai.CallbackArg0) (map[string]interface{}, error) {
    fmt.Printf("Headers = %v\n", (*arg).Headers) // ヘッダー全て
    fmt.Printf("- From: = %s\n", (*arg).Headers["from"][0])
    fmt.Printf("- Subject: = %s\n", (*arg).Headers["subject"][0])
    fmt.Printf("Body = %s\n", (*arg).Payload)    // 本文
    data := make(map[string]interface{})
    data["from"] = (*arg).Headers["from"][0]
    return data, nil
}
args.Callback1 = func(arg *sisimai.CallbackArg1) (bool, error) {
    fmt.Printf("- Path = %s\n", arg.Path)  // 元メールファイルのPATH
    fmt.Printf("- Kind = %s\n", arg.Kind)  // 元メールファイルの種類
    fmt.Printf("Body = %s\n", (*arg.Mail)) // 本文
    fmt.Printf("Fact = %s\n", (*arg.Fact)) // 解析結果
    return true, nil
}

sisi, nyaan := sisimai.Rise(path, args)
                
email

電子メール: rhost-google-03.eml

rhost-google-03.eml にある以下の内容をコールバックで実行するコードによって取得し、元メールへの操作例を示します。

  • バウンスメールのヘッダにあるReturn-Pathの値を取得
  • バウンスメールのヘッダにあるFromの値を取得
  • 本文のX-Postfix-Queue-IDの値を取得
  • STDINからの入力なら元メールを別のPATHへ保存する
Return-Path: <>
Received: from mail4.example.com (mx4.example.com [192.0.2.24])
    by secure.example.jp (Postfix) with ESMTPS id 4SnNbh0r3mz24sXs
    for ; Thu,  9 Apr 2022 23:34:45 +0900 (JST)
Received: by mail4.example.com (Postfix)
    id t8WLKlmm99zqL71C; Thu,  9 Apr 2022 23:34:45 +0900 (JST)
Authentication-Results: secure.example.jp; spf=fail smtp.helo=mail4.example.com
Date: Thu,  9 Apr 2022 23:34:45 +0900 (JST)
From: MAILER-DAEMON@mail4.example.com (Mail Delivery System)
Subject: Undelivered Mail Returned to Sender
To: nginx@mail4.example.com
...
 (expanded from ): host
    gmail-smtp-in.l.google.com[64.233.188.26] said: 550-5.7.26 The MAIL FROM
    domain [mail4.example.com] has an SPF record with a 550-5.7.26 hard fail
    policy (-all) but it fails to pass SPF checks with the ip: 550-5.7.26
    [192.0.2.24]. To best protect our users from spam and phishing,
    550-5.7.26 the message has been blocked. For instructions on setting up
    550-5.7.26 authentication, go to 550 5.7.26
    https://support.google.com/mail/answer/81126#authentication
    2-222222630d46222222b002b2d2neko2cat2222222cat.22 - gsmtp (in reply to end
    of DATA command)

--Lms5yfCw0Vz5CRp3.1647426971/mail4.example.com
Content-Description: Delivery report
Content-Type: message/delivery-status

Reporting-MTA: dns; mail4.example.com
X-Postfix-Queue-ID: Lms5yfCw0Vz5CRp3
X-Postfix-Sender: rfc822; nginx@mail4.example.com
Arrival-Date: Thu,  9 Apr 2022 23:34:45 +0900 (JST)

Final-Recipient: rfc822; kijitora@google.example.com
Original-Recipient: rfc822;neko@example.co.jp
Action: failed
Status: 5.7.26
Remote-MTA: dns; gmail-smtp-in.l.google.com
Diagnostic-Code: smtp; 550-5.7.26 The MAIL FROM domain [mail4.example.com] has
...
                
Perl

Sisimai->rise($f, 'c___' => [$c0, $c1])

Sisimaiクラスのrise()dump() メソッドに、実行したい処理内容を書いたサブルーチンのコードリファレンス2個を第二引数 c___として渡すことができます。

% cat set-of-emails/maildir/bsd/rhost-google-03.eml | perl ./sisid.pl
#! /usr/bin/env perl
# sisid.pl
use Sisimai;
my $c0 = sub {
    my $args = shift;
    my $data = { 'queue-id' => '', 'from' => '', 'return-path' => '' };

    $data->{'return-path'} = $args->{'headers'}->{'return-path'} || '';
    $data->{'from'} = $args->{'headers'}->{'from'} || '';
    if( $args->{'message'} =~ m/^X-Postfix-Queue-ID:\s*(.+)$/m ) {
        $data->{'queue-id'} = $1;
    }
    return $data;
};
my $c1 = sub {
    my $args = shift;
    my $kind = $args->{'kind'}; # (String)  Sisimai::Mail->kind
    my $mail = $args->{'mail'}; # (*String) Entire email message
    my $path = $args->{'path'}; # (String)  Sisimai::Mail->path

    if $kind eq 'stdin' {
        my $f = IO::File->new("/tmp/sisimai-decoded-1.eml", 'w');
        print $f $$mail; $f->close;
    }
};

my $rv = Sisimai->rise(STDIN, 'c___' => [$c0, $c1]);
printf("From: %s\n", $rv->[0]->{'catch'}->{'from'});
printf("Queue-ID: %s\n", $rv->[0]->{'catch'}->{'queue-id'});
printf("Return-Path: %s\n", $rv->[0]->{'catch'}->{'return-path'});
                
Ruby

Sisimai.rise(f, c___: [c0, c1])

Sisimaiクラスのrise()dump()メソッドに、実行したい処理内容を書いた Procオブジェクトをc___: として渡すことができます。

% cat set-of-emails/maildir/bsd/rhost-google-03.eml | ruby ./sisid.rb
#! /usr/bin/env ruby
# sisid.rb
require 'sisimai'
c0 = lambda do |args|
  data = { 'queue-id' => '', 'from' => '', 'return-path' => '' }
  data['return-path'] = args['headers']['return-path'] || ''
  data['from'] = args['headers']['from'] || ''
  if cv = args['message'].match(/^X-Postfix-Queue-ID:\s*(.+)$/)
    data['queue-id'] = cv[1]
  end
  return data
end

c1 = lambda do |args|
  kind = args['kind'] # (String)  Sisimai::Mail.kind
  mail = args['mail'] # (*String) Entire email message
  path = args['path'] # (String)  Sisimai::Mail.path

  if kind == 'stdin'
    File.open("/tmp/sisimai-decoded-1.eml", "w") do |f|
      f.puts(mail)
    end
  end
end

rv = Sisimai.rise(fn, c___: [c0, c1])
printf("From: %s\n", rv[0].catch['from'])
printf("X-Postfix-Queue-ID: %s\n", rv[0].catch['queue-id'])
printf("Return-Path: %s\n", rv[0].catch['return-path'])
                
Go

sisimai.Rise(path, args)

libsisimai.org/sisimaiパッケージのRise()関数と Dump()関数に渡す sis.DecodingArgs 構造体の Callback0Callback1に 実行したい処理内容を書いた関数を代入して渡すことができます。

% cat set-of-emails/maildir/bsd/rhost-google-03.eml | go run ./sisid.go
package main
// sisid.go
import "fmt"
import "strings"
import "libsisimai.org/sisimai"

func main() {
    args := sisimai.Args() // sis.DecodingArgs{}
    list := []string{"Return-Path", "From"}

    args.Callback0 = func(arg *sisimai.CallbackArg0) (map[string]interface{}, error) {
        data := make(map[string]interface{})
        data["queue-id"] = ""

        for _, e := range list {
            ff := strings.ToLower(e)
            if len((*arg).Headers[ff]) == 0 || (*arg).Headers[ff][0] == "" { continue }
            data[ff] = (*arg).Headers[ff][0]
        }

        if arg.Payload != nil && len(*arg.Payload) > 0 {
            name := "X-Postfix-Queue-ID"
            mesg := *arg.Payload
            p0 := strings.Index(mesg, "\n" + name + ": "); if p0 < 0 { return data, nil }
            p1 := p0 + len(name) + 3
            p2 := strings.Index(mesg[p1:], "\n");          if p2 < 0 { return data, nil }
            data["queue-id"] = mesg[p1:p1 + p2]
        }
        return data, nil
    }
    args.Callback1 = func(arg *sisimai.CallbackArg1) (bool, error) {
        if nyaan := ioutil.WriteFile("/tmp/sisimai-decoded-1.eml", []byte(*arg.Mail), 0600); nyaan != nil {
            return false, nyaan
        }
        return true, nil
    }

    // sisi is a pointer to []sis.Facti
    sisi, nyaan := sisimai.Rise("STDIN", args)
    if len(*sisi) > 0 {
        list = append(list, "Queue-ID")
        for _, e := range *sisi {
            // e is a sis.Fact struct
            fmt.Printf("Recipient = %s\n", e.Recipient.Address)
            re, as := e.Catch.(map[string]interface{})
            if as == false { continue }
            for _, f := range list {
                ff := strings.ToLower(f)
                if ca, ok := re[ff].(string); ok {
                    fmt.Printf("- Catch[%s] = %s\n", f, ca)
                }
            }
        }
    }
    // nyaan is a pointer to []sis.NotDecoded
    if len(*nyaan) > 0 { fmt.Fprintf(os.Stderr, "%v\n", *nyaan) }
}
                
JSON

dump()で出力したJSON

Sisimaiクラスのdump() メソッドにフックメソッドを渡して得たJSON文字列は次のような内容になります。

[
  {
    "addresser": "kijitora@google.example.com",
    "messageid": "vDcsF1hr4zzywp69@mail4.example.com",
    "recipient": "kijitora@google.example.com",
    "diagnosticcode": "host gmail-smtp-in.l.google.com[64.233.188.26] said: The MAIL FROM domain [mail4.example.com] has an SPF record with a hard fail policy (-all) but it fails to pass SPF checks with the ip: [192.0.2.24]. To best protect our users from spam and phishing, the message has been blocked. For instructions on setting up authentication, go to https://support.google.com/mail/answer/81126#authentication 2-222222630d46222222b002b2d2neko2cat2222222cat.22 - gsmtp (in reply to end of DATA command)",
    "smtpagent": "Postfix",
    "destination": "google.example.com",
    "alias": "neko@example.co.jp",
    "reason": "authfailure",
    "lhost": "gmail-smtp-in.l.google.com",
    "senderdomain": "google.example.com",
    "token": "fe75b94dd0489b106fa041c460064dd6afa8196b",
    "subject": "Nyaan",
    "deliverystatus": "5.7.26",
    "timezoneoffset": "+0900",
    "listid": "",
    "origin": "set-of-emails/maildir/bsd/rhost-google-03.eml",
    "action": "failed",
    "timestamp": 1649514885,
    "hardbounce": 0,
    "rhost": "gmail-smtp-in.l.google.com",
    "catch": {
      "size": 4436,
      "kind": "Mailbox",
      "from": "MAILER-DAEMON@mail4.example.com (Mail Delivery System)",
      "return-path": "<>",
      "queue-id": "Lms5yfCw0Vz5CRp3",
    },
    "diagnostictype": "SMTP",
    "replycode": 550,
    "feedbacktype": "",
    "smtpcommand": "DATA"
  }
]