sisimai

package module
v5.5.0 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Dec 5, 2025 License: BSD-2-Clause Imports: 9 Imported by: 0

README

License GitHub go.mod Go version Go Reference GitHub Actions Workflow Status Codecov

[!NOTE] Sisimai is a library provided as a Go package that decodes various formats of bounce emails and outputs structured data necessary for analysis, such as destination addresses and bounce reasons. Besides Go, it is very useful for grasping the occurrence status of bounces by obtaining decoded results in any environment as long as it is a language that can read JSON, such as PHP, Java, Python, and Rust.

What is Sisimai

Sisimai (pronounced /ɕi.ɕi.ma.i/) is a Go package, 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.

The key features of Sisimai

  • Decode email bounces to structured data
    • Sisimai provides detailed insights into bounce emails by extracting 27 key data points.[^1]
      • Essential information: Timestamp, Origin
      • Sender information: Addresser, SenderDomain,
      • Recipient information: Recipient, Destination, Alias
      • Delivery information: Action, ReplyCode, DeliveryStatus, Command
      • Bounce details: Reason, DiagnosticCode, DiagnosticType, FeedbackType, FeedbackID, HardBounce
      • Message details: Subject, MessageID, ListID,
      • Additional information: DecodedBy, TimezoneOffset, Lhost, Rhost, Token, Catch, Toxic
    • Output formats
  • Easy to Install, Use.
    • $ go get -u libsisimai.org/sisimai/v5@latest
    • import "libsisimai.org/sisimai/v5"
  • High Precision of Analysis

[^1]: The callback function allows you to add your own data under the Catch field.

Command line demo

The following screen shows a demonstration of Dump function of libsimai.org/sisimai package at the command line using Go(go-sisimai) and jq command.

Setting Up Sisimai

System requirements

More details about system requirements are available at Sisimai | Getting Started page.

  • Go 1.24.0 or later (Sisimai requires Go 1.24 or later since v5.4.0)
  • No external dependencies (excluding standard library) since v5.2.1

Install and Build

Install
$ mkdir ./sisimai
$ cd ./sisimai
$ go mod init example.com/sisimaicli
go: creating new go.mod: module example.com/sisimaicli

$ go get -u libsisimai.org/sisimai/v5@latest
go: added libsisimai.org/sisimai/v5 v5.5.0

$ cat ./go.mod
module example.com/sisimaicli

go 1.25

require (
	libsisimai.org/sisimai/v5 v5.5.0 // indirect
)
Build

For example, the following sisid.go: sisimai decoder is a minimal program that decodes bounce emails and outputs them in JSON format.

$ vi ./sisid.go
// sisimai decoder program
package main
import "os"
import "fmt"
import "libsisimai.org/sisimai/v5"

func main() {
    path := os.Args[1]
    args := sisimai.Args()

    sisi, nyaan := sisimai.Rise(path, args)
    for _, e := range sisi {
        cv, _ := e.Dump()
        fmt.Printf("%s\n",cv)
    }
    if len(nyaan) > 0 { fmt.Frpintf(os.Stderr, "%v\n", nyaan) }
}

Once you have written sisid.go, build an executable binary with go build command.

$ CGO_ENABLED=0 go build -o ./sisid ./sisid.go

Specifying the path to a bounce email (or Maildir/) as the first argument will output the decoded results as a JSON string.

$ ./sisid ./path/to/bounce-mail.eml | jq
{
  "addresser": "michistuna@example.org",
  "recipient": "kijitora@google.example.com",
  "timestamp": 1650119685,
  "action": "failed",
  "alias": "contact@example.co.jp",
  "catch": null,
  "decodedby": "Postfix",
  "deliverystatus": "5.7.26",
  "destination": "google.example.com",
  "diagnosticcode": "host gmail-smtp-in.l.google.com[64.233.187.27] said: This mail has been blocked because the sender is unauthenticated. Gmail requires all senders to authenticate with either SPF or DKIM. Authentication results: DKIM = did not pass SPF [relay3.example.com] with ip: [192.0.2.22] = did not pass For instructions on setting up authentication, go to https://support.google.com/mail/answer/81126#authentication c2-202200202020202020222222cat.127 - gsmtp (in reply to end of DATA command)",
  "diagnostictype": "SMTP",
  "feedbackid": "",
  "feedbacktype": "",
  "hardbounce": false,
  "lhost": "relay3.example.com",
  "listid": "",
  "messageid": "hwK7pzjzJtz0RF9Y@relay3.example.com",
  "origin": "./path/to/bounce-mail.eml",
  "reason": "authfailure",
  "rhost": "gmail-smtp-in.l.google.com",
  "replycode": "550",
  "command": "DATA",
  "senderdomain": "google.example.com",
  "subject": "Nyaan",
  "timezoneoffset": "+0900",
  "token": "5253e9da9dd67573851b057a89cbcf41293e99bf",
  "toxic": false
}

Usage

Basic usage

libsisimai.org/sisimai.Rise() function provides the feature for getting decoded data as []siba.Fact struct, occurred errors as []siba.NotDecoded from bounced email messages as the following.

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

func main() {
    path := os.Args[1]     // go run ./sisid /path/to/mailbox or maildir/
    args := sisimai.Args() // siba.DecodingArgs{}

    // If you also need analysis results that are "delivered" (successfully delivered),
    // set `true` into the "Delivered" option for the Rise() function as shown below.
    args.Delivered = true

    // If you also need analysis results that show a "vacation" reason, set `true` into
    // the "Vacation" option for the Rise() function as shown in the following code.
    args.Vacation  = true

    // sisi is []siba.Fact
    sisi, nyaan := sisimai.Rise(path, args)
    if len(sisi) > 0 {
        for _, e := range sisi {
            // e is a siba.Fact struct
            fmt.Printf("- Sender is %s\n", e.Addresser.Address)
            fmt.Printf("- Recipient is %s\n", e.Recipient.Address)
            fmt.Printf("- Bounced due to %s\n", e.Reason)
            fmt.Printf("- With the error message: %s\n", e.DiagnosticCode)

            cv, _ := e.Dump()     // Convert the decoded data to JSON string
            fmt.Printf("%s\n",cv) // JSON formatted string the jq command can read
        }
    }
    // nyaan is []siba.NotDecoded
    if len(nyaan) > 0 { fmt.Fprintf(os.Stderr, "%v\n", nyaan) }
}

Convert to JSON

The following code snippet illustrates the use of the libsisimai.org/sisimai.Dump() function to obtain decoded bounce email data in JSON array format.

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

func main() {
    path := os.Args[1]
    args := sisimai.Args()

    json, nyaan := sisimai.Dump(path, args)
    if json != nil && *json != "" { fmt.Printf("%s\n", *json) }
    if len(nyaan) > 0 { fmt.Fprintf(os.Stderr, "%v\n", nyaan) }
}

Callback feature

siba.DecodingArgs have the Callback0 and Callback1 fields for keeping callback functions. The former is called at message.sift() for dealitng email headers and entire message body. The latter is called at the end of each email file processing inside of sisimai.Rise().

The results generated by the callback functions are accessible via Catch field defined in siba.Fact.

Callback0: For email headers and the body

The function set in args.Callback0 is called at message.sift().

package main
import "os"
import "fmt"
import "strings"
import "libsisimai.org/sisimai/v5"

func main() {
    path := os.Args[1]     // go run ./sisid /path/to/mailbox or maildir/
    args := sisimai.Args() // siba.DecodingArgs{}

    args.Callback0 = func(arg *sisimai.CallbackArg0) (map[string]interface{}, error) {
        // - This function allows users to add custom processing to the email before parsing.
        // - For example, you can extract the delivery ID from the "X-Delivery-App-ID:" header
        //   and store it in the data map like this: data["x-delivery-app-id"] = "neko22-2".
        // - The library executes this function and assigns the return value to the Catch field of the Fact struct.
        // - Users can then retrieve and access the data from Catch by type assertion in the caller.
        name := "X-Delivery-App-ID"
        data := make(map[string]interface{})
        data[strings.ToLower(name)] = ""

        if arg.Payload != nil && len(*arg.Payload) > 0 {
            mesg := *arg.Payload
            if p0 := strings.Index(mesg, "\n" + name + ":"); p0 > 0 {
                cw := p0 + len(name) + 2
                p1 := strings.Index(mesg[cw:], "\n")
                if p1 > 0 {
                    data[strings.ToLower(name)] = mesg[cw + 1:cw + p1]
                }
            }
        }
        return data, nil
    }

    sisi, _ := sisimai.Rise(path, args)
    if len(sisi) > 0 {
        for _, e := range sisi {
            // e is a siba.Fact struct
            re, as := e.Catch.(map[string]interface{})
            if as == false { continue }
            if ca, ok := re["x-delivery-app-id"].(string); ok {
                fmt.Printf("- Catch[X-Delivery-App-ID] = %s\n", ca)
            }
        }
    }
}
Callback1: For each email file

The function set in args.Callback1 is called at sisimai.Rise() function for dealing each email file after decoding each bounce message.

package main
import "os"
import "io/ioutil"
import "libsisimai.org/sisimai"

func main() {
    path := os.Args[1]     // go run ./sisid /path/to/mailbox or maildir/
    args := sisimai.Args() // siba.DecodingArgs{}

    args.Callback1 = func(arg *sisimai.CallbackArg1) (bool, error) {
        // - This function defines custom operations that the user wants to perform on the parsed email file.
        // - For example, you can write the contents of the parsed bounce email to a file in /tmp/.
        if nyaan := ioutil.WriteFile("/tmp/copy.eml", []byte(*arg.Mail), 0400); nyaan != nil {
            return false, nyaan
        }
        return true, nil
    }

    // sisi is []siba.Fact
    sisi, nyaan := sisimai.Rise(path, args)
    if len(sisi) > 0 {
        for _, e := range sisi {
            // e is a siba.Fact struct
            ...
        }
    }
}

More information about the callback feature is available at Sisimai | How To Parse - Callback Page.

Output example

[
  {
    "addresser": "michistuna@example.org",
    "recipient": "kijitora@google.example.com",
    "timestamp": 1650119685,
    "action": "failed",
    "alias": "contact@example.co.jp",
    "catch": null,
    "decodedby": "Postfix",
    "deliverystatus": "5.7.26",
    "destination": "google.example.com",
    "diagnosticcode": "host gmail-smtp-in.l.google.com[64.233.187.27] said: This mail has been blocked because the sender is unauthenticated. Gmail requires all senders to authenticate with either SPF or DKIM. Authentication results: DKIM = did not pass SPF [relay3.example.com] with ip: [192.0.2.22] = did not pass For instructions on setting up authentication, go to https://support.google.com/mail/answer/81126#authentication c2-202200202020202020222222cat.127 - gsmtp (in reply to end of DATA command)",
    "diagnostictype": "SMTP",
    "feedbackid": "",
    "feedbacktype": "",
    "hardbounce": false,
    "lhost": "relay3.example.com",
    "listid": "",
    "messageid": "hwK7pzjzJtz0RF9Y@relay3.example.com",
    "origin": "./path/to/bounce-mail.eml",
    "reason": "authfailure",
    "rhost": "gmail-smtp-in.l.google.com",
    "replycode": "550",
    "command": "DATA",
    "senderdomain": "google.example.com",
    "subject": "Nyaan",
    "timezoneoffset": "+0900",
    "token": "5253e9da9dd67573851b057a89cbcf41293e99bf",
    "toxic": false
  }
]

Differences between Go and Others

The following table show the differences between the Go version of Sisimai and the other language versions: p5-sisimai and rb-sisimai.

Features

Features Go Perl Ruby / JRuby
System requirements 1.24 - 5.26 - 2.4 - / 9.2 -
Dependencies (Except standard libs) 0 packages 2 modules 1 gem
Supported character sets UTF-8 only UTF-8,etc. [^2] UTF-8,etc.[^3]
Source lines of code 9,200 lines 9,990 lines 9,970 lines
The number of tests 255,000 tests 340,000 tests 240,000 tests
The number of bounce emails decoded/sec [^4] 2900 emails 750 emails 620 emails
License 2 Clause BSD 2 Clause BSD 2 Clause BSD
Commercial support Available Available Available

[^2]: Character sets supported by Encode and Encode::Guess modules [^3]: Character sets supported by String#encode method [^4]: macOS Monterey/1.6GHz Dual-Core Intel Core i5/16GB-RAM/Go 1.22/Perl 5.30/Ruby 2.6.4

Contributing

Bug report

Please use the issue tracker to report any bugs.

Emails could not be decoded

Bounce emails that couldn't be decoded by the latest version of sisimai are saved in the repository set-of-emails/to-be-debugged-because/sisimai-cannot-parse-yet. If you have found any bounce email cannot be decoded using sisimai, please add the email into the directory and send Pull-Request to this repository.

Other Information

See also

Author

@azumakuniyuki and sisimai development team

Copyright (C) 2014-2025 azumakuniyuki and sisimai development team, All Rights Reserved.

License

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

Documentation

Overview

sisimai (pronounced /ɕi.ɕi.ma.i/) 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. More information are available at https://libsisimai.org

Index

Constants

This section is empty.

Variables

This section is empty.

Functions

func Args

func Args() *siba.DecodingArgs

Args returns a pointer to siba.DecodingArgs as the 2nd argument of the Rise function.

func Dump

func Dump(path string, args *siba.DecodingArgs) (*string, []siba.NotDecoded)

Dump returns decoded data as a JSON string.

Arguments:
  - path (string):             Path to an mbox, Maildir/, or "STDIN" for standard input.
  - args (*siba.DecodingArgs): Options and callback functions for decoding bounce messages.
Returns:
  - (*string):           Decoded data as a JSON string array
  - ([]siba.NotDecoded): List of occurred errors

func Factor

func Factor() *siba.Fact

Factor retuns empty (initialized with zero values) siba.Fact instance.

func Reason

func Reason() map[string]string

Reason returns the list of bounce reasons sisimai can detect.

func Rise

func Rise(path string, args *siba.DecodingArgs) ([]siba.Fact, []siba.NotDecoded)

Rise is a function for decoding bounce mails in a mailbox or a Maildir/.

Arguments:
  - path (string):             Path to an UNIX mbox, Maildir/, or "STDIN" for standard input.
  - args (*siba.DecodingArgs): Options and callback functions for decoding bounce messages.
Returns:
  - ([]siba.Fact):       List of successfully decoded bounce messages.
  - ([]siba.NotDecoded): List of occurred errors.

func Version

func Version() string

Version returns the version number of sisimai such as "v5.2.0" or "v5.2.1p22".

Types

type CallbackArg0

type CallbackArg0 = siba.CallbackArg0

type CallbackArg1

type CallbackArg1 = siba.CallbackArg1

type CfParameter0

type CfParameter0 = siba.CfParameter0

type CfParameter1

type CfParameter1 = siba.CfParameter1

Directories

Path Synopsis
Package "address" provide functions related to an email address.
Package "address" provide functions related to an email address.
Package "arf" provides ARF: Abuse Report Format related functions.
Package "arf" provides ARF: Abuse Report Format related functions.
Package "eb" provides constants for the email bounce.
Package "eb" provides constants for the email bounce.
Package "fact" provide a function for generating structs keeping decoded bounce mail data.
Package "fact" provide a function for generating structs keeping decoded bounce mail data.
Package "lda" provides a function to detect a bounce reason due to errors returned from LDA.
Package "lda" provides a function to detect a bounce reason due to errors returned from LDA.
Package "lhost" provides functions for decoding bounce messages generated by various MTAs such as Sendmail, Postfix, OpenSMTPD, some commercial mail servers, and other email services.
Package "lhost" provides functions for decoding bounce messages generated by various MTAs such as Sendmail, Postfix, OpenSMTPD, some commercial mail servers, and other email services.
Package "mail" provides funtions for reading a UNIX mbox, a Maildir, or any email message input from Standard-in.
Package "mail" provides funtions for reading a UNIX mbox, a Maildir, or any email message input from Standard-in.
Package "message" provides functions to read email message as a string, to tidy up each line.
Package "message" provides functions to read email message as a string, to tidy up each line.
Package "moji" provides functions for dealing strings.
Package "moji" provides functions for dealing strings.
Package "reason" provides functions for detecting the bounce reason by matching many error message patterns defined in why-*.go files.
Package "reason" provides functions for detecting the bounce reason by matching many error message patterns defined in why-*.go files.
package "rfc1123" provides functions related to Internet hosts described in RFC1123.
package "rfc1123" provides functions related to Internet hosts described in RFC1123.
Package "rfc1894" provides funtions related to RFC1894; An Extensible Message Format for Delivery Status Notifications.
Package "rfc1894" provides funtions related to RFC1894; An Extensible Message Format for Delivery Status Notifications.
Package "rfc2045" provides functions for RFC2045; Multipurpose Internet Mail Extensions (MIME) Part One: Format of Internet Message Bodies.
Package "rfc2045" provides functions for RFC2045; Multipurpose Internet Mail Extensions (MIME) Part One: Format of Internet Message Bodies.
Package "rfc3464" provides functions like a MTA module in "lhost" package for decoding bounce messages formatted according to RFC3464; An Extensible Message Format for Delivery Status Notifications.
Package "rfc3464" provides functions like a MTA module in "lhost" package for decoding bounce messages formatted according to RFC3464; An Extensible Message Format for Delivery Status Notifications.
Package "rfc3834" provides functions like a MTA module in "lhost" package for decoding automatic responded messages formatted according to RFC3834; Recommendations for Automatic Responses to Electronic Mail.
Package "rfc3834" provides functions like a MTA module in "lhost" package for decoding automatic responded messages formatted according to RFC3834; Recommendations for Automatic Responses to Electronic Mail.
Package "rfc5322" provides functions for email addresses, Date: header, Received: headers, and other headers and messages related to RFC5322.
Package "rfc5322" provides functions for email addresses, Date: header, Received: headers, and other headers and messages related to RFC5322.
Package "rfc5965" provides a function related to RFC5965; An Extensible Format for Email Feedback Reports.
Package "rfc5965" provides a function related to RFC5965; An Extensible Format for Email Feedback Reports.
Package "rfc791" provides functions related to IPv4 address described in RFC791.
Package "rfc791" provides functions related to IPv4 address described in RFC791.
Package "rhost" provides functions for detecting bounce reason by matching error codes or error error message patterns described in documents of each email services.
Package "rhost" provides functions for detecting bounce reason by matching error codes or error error message patterns described in documents of each email services.
Package "siba" provides types for data structure of sisimai SIBA stands for Sisimai Internal Bounce Abstraction.
Package "siba" provides types for data structure of sisimai SIBA stands for Sisimai Internal Bounce Abstraction.
smtp
command
Package "smtp/command" provides functions related to SMTP commands.
Package "smtp/command" provides functions related to SMTP commands.
failure
Package "smtp/failure" provides functions related to SMTP errors.
Package "smtp/failure" provides functions related to SMTP errors.
reply
Package "smtp/reply" provides funtions related to SMTP reply codes such as 421, 550.
Package "smtp/reply" provides funtions related to SMTP reply codes such as 421, 550.
status
Package "smtp/status" provides functions related to SMTP Status codes such as 4.2.2, 5.1.1.
Package "smtp/status" provides functions related to SMTP Status codes such as 4.2.2, 5.1.1.
transcript
Package "smtp/transcript" provides functions related to SMTP transcript logs.
Package "smtp/transcript" provides functions related to SMTP transcript logs.

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL