Module: Sisimai::Lhost::OpenSMTPD

Defined in:
lib/sisimai/lhost/opensmtpd.rb

Overview

Sisimai::Lhost::OpenSMTPD decodes a bounce email which created by OpenSMTPD www.opensmtpd.org/. Methods in the module are called from only Sisimai::Message.

Constant Summary collapse

Indicators =
Sisimai::Lhost.INDICATORS
Boundaries =
['    Below is a copy of the original message:'].freeze
StartingOf =
{
  # http://www.openbsd.org/cgi-bin/man.cgi?query=smtpd&sektion=8
  # opensmtpd-5.4.2p1/smtpd/
  #   bounce.c/317:#define NOTICE_INTRO \
  #   bounce.c/318:    "    Hi!\n\n"    \
  #   bounce.c/319:    "    This is the MAILER-DAEMON, please DO NOT REPLY to this e-mail.\n"
  #   bounce.c/320:
  #   bounce.c/321:const char *notice_error =
  #   bounce.c/322:    "    An error has occurred while attempting to deliver a message for\n"
  #   bounce.c/323:    "    the following list of recipients:\n\n";
  #   bounce.c/324:
  #   bounce.c/325:const char *notice_warning =
  #   bounce.c/326:    "    A message is delayed for more than %s for the following\n"
  #   bounce.c/327:    "    list of recipients:\n\n";
  #   bounce.c/328:
  #   bounce.c/329:const char *notice_warning2 =
  #   bounce.c/330:    "    Please note that this is only a temporary failure report.\n"
  #   bounce.c/331:    "    The message is kept in the queue for up to %s.\n"
  #   bounce.c/332:    "    You DO NOT NEED to re-send the message to these recipients.\n\n";
  #   bounce.c/333:
  #   bounce.c/334:const char *notice_success =
  #   bounce.c/335:    "    Your message was successfully delivered to these recipients.\n\n";
  #   bounce.c/336:
  #   bounce.c/337:const char *notice_relay =
  #   bounce.c/338:    "    Your message was relayed to these recipients.\n\n";
  #   bounce.c/339:
  message: ['    This is the MAILER-DAEMON, please DO NOT REPLY to this '],
}.freeze

Class Method Summary collapse

Class Method Details

.descriptionObject



92
# File 'lib/sisimai/lhost/opensmtpd.rb', line 92

def description; return 'OpenSMTPD'; end

.inquire(mhead, mbody) ⇒ Hash, Nil

This method is abstract.

Decodes the bounce message from OpenSMTPD

Parameters:

  • mhead (Hash)

    Message headers of a bounce email

  • mbody (String)

    Message body of a bounce email

Returns:

  • (Hash)

    Bounce data list and message/rfc822 part

  • (Nil)

    it failed to decode or the arguments are missing



44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
# File 'lib/sisimai/lhost/opensmtpd.rb', line 44

def inquire(mhead, mbody)
  return nil if mhead['subject'].start_with?('Delivery status notification') == false
  return nil if mhead['from'].start_with?('Mailer Daemon <') == false
  return nil if mhead['received'].none? { |a| a.include?(' (OpenSMTPD) with ') }

  dscontents = [Sisimai::Lhost.DELIVERYSTATUS]; v = nil
  emailparts = Sisimai::RFC5322.part(mbody, Boundaries)
  bodyslices = emailparts[0].split("\n")
  readcursor = 0      # (Integer) Points the current cursor position
  recipients = 0      # (Integer) The number of 'Final-Recipient' header

  while e = bodyslices.shift do
    # Read error messages and delivery status lines from the head of the email to the previous
    # line of the beginning of the original message.
    if readcursor == 0
      # Beginning of the bounce message or delivery status part
      readcursor |= Indicators[:deliverystatus] if e.start_with?(StartingOf[:message][0])
      next
    end
    next if (readcursor & Indicators[:deliverystatus]) == 0 || e.empty?

    #    Hi!
    #
    #    This is the MAILER-DAEMON, please DO NOT REPLY to this e-mail.
    #
    #    An error has occurred while attempting to deliver a message for
    #    the following list of recipients:
    #
    # kijitora@example.jp: 550 5.2.2 <kijitora@example>... Mailbox Full
    #
    #    Below is a copy of the original message:
    v = dscontents[-1]

    if Sisimai::String.aligned(e, ['@', ' '])
      # kijitora@example.jp: 550 5.2.2 <kijitora@example>... Mailbox Full
      if v["recipient"] != ""
        # There are multiple recipient addresses in the message body.
        dscontents << Sisimai::Lhost.DELIVERYSTATUS
        v = dscontents[-1]
      end
      v['recipient'] = e[0, e.index(':')]
      v['diagnosis'] = e[e.index(':') + 1, e.size]
      recipients += 1
    end
  end
  return nil if recipients == 0
  return { 'ds' => dscontents, 'rfc822' => emailparts[1] }
end