Module: Sisimai::Lhost::X6

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

Overview

Sisimai::Lhost::X6 decodes a bounce email which created by Unknown MTA #6. Methods in the module are called from only Sisimai::Message.

Constant Summary collapse

Indicators =
Sisimai::Lhost.INDICATORS
Boundaries =
['The attachment contains the original mail headers'].freeze
StartingOf =
{message: ['We had trouble delivering your message. Full details follow:']}.freeze

Class Method Summary collapse

Class Method Details

.descriptionObject



91
# File 'lib/sisimai/lhost/x6.rb', line 91

def description; return 'Unknown MTA #6'; end

.inquire(mhead, mbody) ⇒ Hash, Nil

This method is abstract.

Decodes the bounce message from Unknown MTA #6

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

Since:

  • v4.25.6



18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
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
# File 'lib/sisimai/lhost/x6.rb', line 18

def inquire(mhead, mbody)
  return nil if mhead['subject'].start_with?('There was an error sending your mail') == false

  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?

    # We had trouble delivering your message. Full details follow:
    #
    # Subject: 'Nyaan'
    # Date: 'Thu, 29 Apr 2012 23:34:45 +0000'
    #          
    # 1 error(s):
    #
    # SMTP Server <mta2.example.jp> rejected recipient <kijitora@examplejp> 
    #   (Error following RCPT command). It responded as follows: [550 5.1.1 User unknown]v = dscontents[-1]
    v  = dscontents[-1]
    p1 = e.index('The following recipients returned permanent errors: ')
    p2 = e.index('SMTP Server <')

    if p1 == 0 || p2 == 0
      # SMTP Server <mta2.example.jp> rejected recipient <kijitora@examplejp> 
      # The following recipients returned permanent errors: neko@example.jp.
      if v["recipient"] != ""
        # There are multiple recipient addresses in the message body.
        dscontents << Sisimai::Lhost.DELIVERYSTATUS
        v = dscontents[-1]
      end

      if p1 == 0
        # The following recipients returned permanent errors: neko@example.jp.
        p1 = e.index('errors: ')
        p2 = e.index(' ', p1 + 8)
        v['recipient'] = Sisimai::Address.s3s4(e[p1 + 8, p2 - p1 - 8])

      elsif p2 == 0
        # SMTP Server <mta2.example.jp> rejected recipient <kijitora@examplejp> 
        p1 = e.rindex('<')
        p2 = e.rindex('>')
        v['recipient'] = Sisimai::Address.s3s4(e[p1, p2 - p1])

      else
        next
      end

      v['diagnosis'] = e
      recipients += 1
    end
  end
  return nil if recipients == 0

  require 'sisimai/smtp/command'
  dscontents.each do |e|
    if cv = Sisimai::SMTP::Command.find(e['diagnosis'])
      # ...(Error following RCPT command).
      e['command'] = cv
    end
  end

  return {"ds" => dscontents, "rfc822" => emailparts[1]}
end