sisimai 4.25.4 → 4.25.5

Sign up to get free protection for your applications and to get access to all the features.

Potentially problematic release.


This version of sisimai might be problematic. Click here for more details.

Files changed (100) hide show
  1. checksums.yaml +4 -4
  2. data/.travis.yml +2 -2
  3. data/ChangeLog.md +50 -0
  4. data/README-JA.md +10 -37
  5. data/README.md +10 -37
  6. data/lib/sisimai.rb +15 -64
  7. data/lib/sisimai/address.rb +13 -17
  8. data/lib/sisimai/arf.rb +4 -4
  9. data/lib/sisimai/data.rb +3 -5
  10. data/lib/sisimai/lhost.rb +0 -14
  11. data/lib/sisimai/lhost/activehunter.rb +31 -55
  12. data/lib/sisimai/lhost/amavis.rb +41 -66
  13. data/lib/sisimai/lhost/amazonses.rb +189 -235
  14. data/lib/sisimai/lhost/amazonworkmail.rb +48 -71
  15. data/lib/sisimai/lhost/aol.rb +49 -75
  16. data/lib/sisimai/lhost/apachejames.rb +60 -83
  17. data/lib/sisimai/lhost/bigfoot.rb +61 -85
  18. data/lib/sisimai/lhost/biglobe.rb +40 -62
  19. data/lib/sisimai/lhost/courier.rb +60 -82
  20. data/lib/sisimai/lhost/domino.rb +50 -76
  21. data/lib/sisimai/lhost/einsundeins.rb +57 -55
  22. data/lib/sisimai/lhost/exchange2003.rb +79 -101
  23. data/lib/sisimai/lhost/exchange2007.rb +66 -74
  24. data/lib/sisimai/lhost/exim.rb +119 -142
  25. data/lib/sisimai/lhost/ezweb.rb +53 -73
  26. data/lib/sisimai/lhost/facebook.rb +49 -75
  27. data/lib/sisimai/lhost/fml.rb +25 -50
  28. data/lib/sisimai/lhost/gmx.rb +55 -79
  29. data/lib/sisimai/lhost/google.rb +39 -66
  30. data/lib/sisimai/lhost/gsuite.rb +74 -94
  31. data/lib/sisimai/lhost/imailserver.rb +34 -67
  32. data/lib/sisimai/lhost/interscanmss.rb +33 -67
  33. data/lib/sisimai/lhost/kddi.rb +30 -52
  34. data/lib/sisimai/lhost/mailfoundry.rb +35 -57
  35. data/lib/sisimai/lhost/mailmarshalsmtp.rb +66 -89
  36. data/lib/sisimai/lhost/mailru.rb +51 -76
  37. data/lib/sisimai/lhost/mcafee.rb +53 -79
  38. data/lib/sisimai/lhost/messagelabs.rb +49 -75
  39. data/lib/sisimai/lhost/messagingserver.rb +91 -113
  40. data/lib/sisimai/lhost/mfilter.rb +50 -70
  41. data/lib/sisimai/lhost/mxlogic.rb +38 -63
  42. data/lib/sisimai/lhost/notes.rb +53 -82
  43. data/lib/sisimai/lhost/office365.rb +64 -81
  44. data/lib/sisimai/lhost/opensmtpd.rb +30 -52
  45. data/lib/sisimai/lhost/outlook.rb +49 -75
  46. data/lib/sisimai/lhost/postfix.rb +116 -117
  47. data/lib/sisimai/lhost/qmail.rb +33 -55
  48. data/lib/sisimai/lhost/receivingses.rb +49 -75
  49. data/lib/sisimai/lhost/sendgrid.rb +68 -203
  50. data/lib/sisimai/lhost/sendmail.rb +101 -125
  51. data/lib/sisimai/lhost/surfcontrol.rb +53 -79
  52. data/lib/sisimai/lhost/userdefined.rb +15 -35
  53. data/lib/sisimai/lhost/v5sendmail.rb +59 -89
  54. data/lib/sisimai/lhost/verizon.rb +75 -124
  55. data/lib/sisimai/lhost/x1.rb +30 -54
  56. data/lib/sisimai/lhost/x2.rb +28 -52
  57. data/lib/sisimai/lhost/x3.rb +44 -68
  58. data/lib/sisimai/lhost/x4.rb +34 -58
  59. data/lib/sisimai/lhost/x5.rb +42 -70
  60. data/lib/sisimai/lhost/yahoo.rb +44 -68
  61. data/lib/sisimai/lhost/yandex.rb +59 -85
  62. data/lib/sisimai/lhost/zoho.rb +54 -78
  63. data/lib/sisimai/mail.rb +5 -9
  64. data/lib/sisimai/mail/maildir.rb +10 -14
  65. data/lib/sisimai/mail/mbox.rb +8 -12
  66. data/lib/sisimai/mail/memory.rb +5 -9
  67. data/lib/sisimai/mail/stdin.rb +7 -11
  68. data/lib/sisimai/mda.rb +2 -2
  69. data/lib/sisimai/message.rb +51 -154
  70. data/lib/sisimai/mime.rb +2 -2
  71. data/lib/sisimai/order.rb +2 -27
  72. data/lib/sisimai/reason.rb +3 -5
  73. data/lib/sisimai/rfc1894.rb +1 -1
  74. data/lib/sisimai/rfc3464.rb +29 -29
  75. data/lib/sisimai/rfc3834.rb +7 -6
  76. data/lib/sisimai/rfc5322.rb +20 -31
  77. data/lib/sisimai/rhost/franceptt.rb +120 -24
  78. data/lib/sisimai/rhost/iua.rb +1 -1
  79. data/lib/sisimai/smtp/error.rb +7 -7
  80. data/lib/sisimai/version.rb +1 -1
  81. data/set-of-emails/maildir/bsd/email-einsundeins-03.eml +66 -0
  82. data/set-of-emails/maildir/bsd/email-exchange2007-05.eml +1469 -0
  83. data/set-of-emails/maildir/bsd/email-exchange2007-06.eml +764 -0
  84. data/set-of-emails/maildir/bsd/email-postfix-64.eml +96 -0
  85. data/set-of-emails/maildir/bsd/rfc3834-03.eml +26 -0
  86. data/set-of-emails/maildir/bsd/rhost-franceptt-04.eml +66 -0
  87. data/set-of-emails/maildir/bsd/rhost-franceptt-05.eml +96 -0
  88. data/set-of-emails/maildir/bsd/rhost-franceptt-06.eml +100 -0
  89. data/set-of-emails/maildir/bsd/rhost-franceptt-07.eml +97 -0
  90. data/set-of-emails/maildir/bsd/rhost-franceptt-08.eml +78 -0
  91. data/set-of-emails/maildir/bsd/rhost-franceptt-10.eml +79 -0
  92. data/set-of-emails/maildir/bsd/rhost-franceptt-11.eml +96 -0
  93. metadata +14 -9
  94. data/lib/sisimai/bite.rb +0 -42
  95. data/lib/sisimai/bite/email.rb +0 -18
  96. data/lib/sisimai/bite/json.rb +0 -16
  97. data/lib/sisimai/message/email.rb +0 -26
  98. data/lib/sisimai/message/json.rb +0 -24
  99. data/lib/sisimai/order/email.rb +0 -20
  100. data/lib/sisimai/order/json.rb +0 -16
@@ -7,12 +7,7 @@ module Sisimai::Lhost
7
7
  # Imported from p5-Sisimail/lib/Sisimai/Lhost/InterScanMSS.pm
8
8
  require 'sisimai/lhost'
9
9
 
10
- Indicators = Sisimai::Lhost.INDICATORS
11
- StartingOf = {
12
- message: [''],
13
- rfc822: ['Content-type: message/rfc822'],
14
- }.freeze
15
-
10
+ ReBackbone = %r|^Content-type:[ ]message/rfc822|.freeze
16
11
  def description; return 'Trend Micro InterScan Messaging Security Suite'; end
17
12
  def smtpagent; return Sisimai::Lhost.smtpagent(self); end
18
13
  def headerlist; return []; end
@@ -41,77 +36,49 @@ module Sisimai::Lhost
41
36
  return nil unless match > 0
42
37
 
43
38
  dscontents = [Sisimai::Lhost.DELIVERYSTATUS]
44
- hasdivided = mbody.split("\n")
45
- rfc822list = [] # (Array) Each line in message/rfc822 part string
46
- blanklines = 0 # (Integer) The number of blank lines
47
- readcursor = 0 # (Integer) Points the current cursor position
39
+ emailsteak = Sisimai::RFC5322.fillet(mbody, ReBackbone)
40
+ bodyslices = emailsteak[0].split("\n")
48
41
  recipients = 0 # (Integer) The number of 'Final-Recipient' header
49
42
  v = nil
50
43
 
51
- while e = hasdivided.shift do
52
- if readcursor == 0
53
- # Beginning of the bounce message or delivery status part
54
- if e.start_with?(StartingOf[:message][0])
55
- readcursor |= Indicators[:deliverystatus]
56
- next
57
- end
58
- end
59
-
60
- if (readcursor & Indicators[:'message-rfc822']) == 0
61
- # Beginning of the original message part
62
- if e.start_with?(StartingOf[:rfc822][0])
63
- readcursor |= Indicators[:'message-rfc822']
64
- next
65
- end
66
- end
44
+ while e = bodyslices.shift do
45
+ # Read error messages and delivery status lines from the head of the email
46
+ # to the previous line of the beginning of the original message.
47
+ next if e.empty?
67
48
 
68
- if readcursor & Indicators[:'message-rfc822'] > 0
69
- # Inside of the original message part
70
- if e.empty?
71
- blanklines += 1
72
- break if blanklines > 1
73
- next
74
- end
75
- rfc822list << e
76
- else
77
- # Error message part
78
- next if (readcursor & Indicators[:deliverystatus]) == 0
79
- next if e.empty?
49
+ # Sent <<< RCPT TO:<kijitora@example.co.jp>
50
+ # Received >>> 550 5.1.1 <kijitora@example.co.jp>... user unknown
51
+ v = dscontents[-1]
80
52
 
53
+ if cv = e.match(/\A.+[<>]{3}[ \t]+.+[<]([^ ]+[@][^ ]+)[>]\z/) ||
54
+ e.match(/\A.+[<>]{3}[ \t]+.+[<]([^ ]+[@][^ ]+)[>]/)
81
55
  # Sent <<< RCPT TO:<kijitora@example.co.jp>
82
56
  # Received >>> 550 5.1.1 <kijitora@example.co.jp>... user unknown
83
- v = dscontents[-1]
84
-
85
- if cv = e.match(/\A.+[<>]{3}[ \t]+.+[<]([^ ]+[@][^ ]+)[>]\z/) ||
86
- e.match(/\A.+[<>]{3}[ \t]+.+[<]([^ ]+[@][^ ]+)[>]/)
87
- # Sent <<< RCPT TO:<kijitora@example.co.jp>
88
- # Received >>> 550 5.1.1 <kijitora@example.co.jp>... user unknown
89
- if v['recipient'] && cv[1] != v['recipient']
90
- # There are multiple recipient addresses in the message body.
91
- dscontents << Sisimai::Lhost.DELIVERYSTATUS
92
- v = dscontents[-1]
93
- end
94
- v['recipient'] = cv[1]
95
- recipients = dscontents.size
57
+ if v['recipient'] && cv[1] != v['recipient']
58
+ # There are multiple recipient addresses in the message body.
59
+ dscontents << Sisimai::Lhost.DELIVERYSTATUS
60
+ v = dscontents[-1]
96
61
  end
62
+ v['recipient'] = cv[1]
63
+ recipients = dscontents.size
64
+ end
65
+
66
+ if cv = e.match(/\ASent[ ]+[<]{3}[ ]+([A-Z]{4})[ ]/)
67
+ # Sent <<< RCPT TO:<kijitora@example.co.jp>
68
+ v['command'] = cv[1]
97
69
 
98
- if cv = e.match(/\ASent[ ]+[<]{3}[ ]+([A-Z]{4})[ ]/)
99
- # Sent <<< RCPT TO:<kijitora@example.co.jp>
70
+ elsif cv = e.match(/\AReceived[ ]+[>]{3}[ ]+(\d{3}[ ]+.+)\z/)
71
+ # Received >>> 550 5.1.1 <kijitora@example.co.jp>... user unknown
72
+ v['diagnosis'] = cv[1]
73
+ else
74
+ # Error message in non-English
75
+ if cv = e.match(/[ ][>]{3}[ ]([A-Z]{4})/)
76
+ # >>> RCPT TO ...
100
77
  v['command'] = cv[1]
101
78
 
102
- elsif cv = e.match(/\AReceived[ ]+[>]{3}[ ]+(\d{3}[ ]+.+)\z/)
103
- # Received >>> 550 5.1.1 <kijitora@example.co.jp>... user unknown
79
+ elsif cv = e.match(/[ ][<]{3}[ ](.+)/)
80
+ # <<< 550 5.1.1 User unknown
104
81
  v['diagnosis'] = cv[1]
105
- else
106
- # Error message in non-English
107
- if cv = e.match(/[ ][>]{3}[ ]([A-Z]{4})/)
108
- # >>> RCPT TO ...
109
- v['command'] = cv[1]
110
-
111
- elsif cv = e.match(/[ ][<]{3}[ ](.+)/)
112
- # <<< 550 5.1.1 User unknown
113
- v['diagnosis'] = cv[1]
114
- end
115
82
  end
116
83
  end
117
84
  end
@@ -123,8 +90,7 @@ module Sisimai::Lhost
123
90
  e.each_key { |a| e[a] ||= '' }
124
91
  end
125
92
 
126
- rfc822part = Sisimai::RFC5322.weedout(rfc822list)
127
- return { 'ds' => dscontents, 'rfc822' => rfc822part }
93
+ return { 'ds' => dscontents, 'rfc822' => emailsteak[1] }
128
94
  end
129
95
 
130
96
  end
@@ -7,7 +7,7 @@ module Sisimai::Lhost
7
7
  require 'sisimai/lhost'
8
8
 
9
9
  Indicators = Sisimai::Lhost.INDICATORS
10
- StartingOf = { rfc822: ['Content-Type: message/rfc822'] }.freeze
10
+ ReBackbone = %r|^Content-Type:[ ]message/rfc822|.freeze
11
11
  MarkingsOf = {
12
12
  message: %r/\AYour[ ]mail[ ](?:
13
13
  sent[ ]on:?[ ][A-Z][a-z]{2}[,]
@@ -46,66 +46,45 @@ module Sisimai::Lhost
46
46
  return nil unless match > 0
47
47
 
48
48
  dscontents = [Sisimai::Lhost.DELIVERYSTATUS]
49
- hasdivided = mbody.split("\n")
50
- rfc822list = [] # (Array) Each line in message/rfc822 part string
51
- blanklines = 0 # (Integer) The number of blank lines
49
+ emailsteak = Sisimai::RFC5322.fillet(mbody, ReBackbone)
50
+ bodyslices = emailsteak[0].split("\n")
52
51
  readcursor = 0 # (Integer) Points the current cursor position
53
52
  recipients = 0 # (Integer) The number of 'Final-Recipient' header
54
53
  v = nil
55
54
 
56
- while e = hasdivided.shift do
55
+ while e = bodyslices.shift do
56
+ # Read error messages and delivery status lines from the head of the email
57
+ # to the previous line of the beginning of the original message.
57
58
  if readcursor == 0
58
59
  # Beginning of the bounce message or delivery status part
59
- if e =~ MarkingsOf[:message]
60
- readcursor |= Indicators[:deliverystatus]
61
- next
62
- end
60
+ readcursor |= Indicators[:deliverystatus] if e =~ MarkingsOf[:message]
61
+ next
63
62
  end
63
+ next if (readcursor & Indicators[:deliverystatus]) == 0
64
+ next if e.empty?
64
65
 
65
- if (readcursor & Indicators[:'message-rfc822']) == 0
66
- # Beginning of the original message part
67
- if e == StartingOf[:rfc822][0]
68
- readcursor |= Indicators[:'message-rfc822']
69
- next
66
+ v = dscontents[-1]
67
+ if cv = e.match(/\A[ \t]+Could not be delivered to: [<]([^ ]+[@][^ ]+)[>]/)
68
+ # Your mail sent on: Thu, 29 Apr 2010 11:04:47 +0900
69
+ # Could not be delivered to: <******@**.***.**>
70
+ # As their mailbox is full.
71
+ if v['recipient']
72
+ # There are multiple recipient addresses in the message body.
73
+ dscontents << Sisimai::Lhost.DELIVERYSTATUS
74
+ v = dscontents[-1]
70
75
  end
71
- end
76
+ r = Sisimai::Address.s3s4(cv[1])
77
+ next unless Sisimai::RFC5322.is_emailaddress(r)
78
+ v['recipient'] = r
79
+ recipients += 1
72
80
 
73
- if readcursor & Indicators[:'message-rfc822'] > 0
74
- # Inside of the original message part
75
- if e.empty?
76
- blanklines += 1
77
- break if blanklines > 1
78
- next
79
- end
80
- rfc822list << e
81
+ elsif cv = e.match(/Your mail sent on: (.+)\z/)
82
+ # Your mail sent on: Thu, 29 Apr 2010 11:04:47 +0900
83
+ v['date'] = cv[1]
81
84
  else
82
- # Error message part
83
- next if (readcursor & Indicators[:deliverystatus]) == 0
84
- next if e.empty?
85
-
86
- v = dscontents[-1]
87
- if cv = e.match(/\A[ \t]+Could not be delivered to: [<]([^ ]+[@][^ ]+)[>]/)
88
- # Your mail sent on: Thu, 29 Apr 2010 11:04:47 +0900
89
- # Could not be delivered to: <******@**.***.**>
90
- # As their mailbox is full.
91
- if v['recipient']
92
- # There are multiple recipient addresses in the message body.
93
- dscontents << Sisimai::Lhost.DELIVERYSTATUS
94
- v = dscontents[-1]
95
- end
96
- r = Sisimai::Address.s3s4(cv[1])
97
- next unless Sisimai::RFC5322.is_emailaddress(r)
98
- v['recipient'] = r
99
- recipients += 1
100
-
101
- elsif cv = e.match(/Your mail sent on: (.+)\z/)
102
- # Your mail sent on: Thu, 29 Apr 2010 11:04:47 +0900
103
- v['date'] = cv[1]
104
- else
105
- # As their mailbox is full.
106
- v['diagnosis'] ||= ''
107
- v['diagnosis'] << e + ' ' if e.start_with?(' ', "\t")
108
- end
85
+ # As their mailbox is full.
86
+ v['diagnosis'] ||= ''
87
+ v['diagnosis'] << e + ' ' if e.start_with?(' ', "\t")
109
88
  end
110
89
  end
111
90
  return nil unless recipients > 0
@@ -136,8 +115,7 @@ module Sisimai::Lhost
136
115
 
137
116
  end
138
117
 
139
- rfc822part = Sisimai::RFC5322.weedout(rfc822list)
140
- return { 'ds' => dscontents, 'rfc822' => rfc822part }
118
+ return { 'ds' => dscontents, 'rfc822' => emailsteak[1] }
141
119
  end
142
120
 
143
121
  end
@@ -7,9 +7,9 @@ module Sisimai::Lhost
7
7
  require 'sisimai/lhost'
8
8
 
9
9
  Indicators = Sisimai::Lhost.INDICATORS
10
+ ReBackbone = %r|^Content-Type:[ ]message/rfc822|.freeze
10
11
  StartingOf = {
11
12
  message: ['This is a MIME encoded message'],
12
- rfc822: ['Content-Type: message/rfc822'],
13
13
  error: ['Delivery failed for the following reason:'],
14
14
  }.freeze
15
15
 
@@ -33,73 +33,52 @@ module Sisimai::Lhost
33
33
  return nil unless mhead['received'].any? { |a| a.include?('(MAILFOUNDRY) id ') }
34
34
 
35
35
  dscontents = [Sisimai::Lhost.DELIVERYSTATUS]
36
- hasdivided = mbody.split("\n")
37
- rfc822list = [] # (Array) Each line in message/rfc822 part string
38
- blanklines = 0 # (Integer) The number of blank lines
36
+ emailsteak = Sisimai::RFC5322.fillet(mbody, ReBackbone)
37
+ bodyslices = emailsteak[0].split("\n")
39
38
  readcursor = 0 # (Integer) Points the current cursor position
40
39
  recipients = 0 # (Integer) The number of 'Final-Recipient' header
41
40
  v = nil
42
41
 
43
- while e = hasdivided.shift do
42
+ while e = bodyslices.shift do
43
+ # Read error messages and delivery status lines from the head of the email
44
+ # to the previous line of the beginning of the original message.
44
45
  if readcursor == 0
45
46
  # Beginning of the bounce message or delivery status part
46
- if e == StartingOf[:message][0]
47
- readcursor |= Indicators[:deliverystatus]
48
- next
49
- end
47
+ readcursor |= Indicators[:deliverystatus] if e == StartingOf[:message][0]
48
+ next
50
49
  end
50
+ next if (readcursor & Indicators[:deliverystatus]) == 0
51
+ next if e.empty?
51
52
 
52
- if (readcursor & Indicators[:'message-rfc822']) == 0
53
- # Beginning of the original message part
54
- if e == StartingOf[:rfc822][0]
55
- readcursor |= Indicators[:'message-rfc822']
56
- next
57
- end
58
- end
53
+ # Unable to deliver message to: <kijitora@example.org>
54
+ # Delivery failed for the following reason:
55
+ # Server mx22.example.org[192.0.2.222] failed with: 550 <kijitora@example.org> No such user here
56
+ #
57
+ # This has been a permanent failure. No further delivery attempts will be made.
58
+ v = dscontents[-1]
59
59
 
60
- if readcursor & Indicators[:'message-rfc822'] > 0
61
- # Inside of the original message part
62
- if e.empty?
63
- blanklines += 1
64
- break if blanklines > 1
65
- next
60
+ if cv = e.match(/\AUnable to deliver message to: [<]([^ ]+[@][^ ]+)[>]\z/)
61
+ # Unable to deliver message to: <kijitora@example.org>
62
+ if v['recipient']
63
+ # There are multiple recipient addresses in the message body.
64
+ dscontents << Sisimai::Lhost.DELIVERYSTATUS
65
+ v = dscontents[-1]
66
66
  end
67
- rfc822list << e
67
+ v['recipient'] = cv[1]
68
+ recipients += 1
68
69
  else
69
- # Error message part
70
- next if (readcursor & Indicators[:deliverystatus]) == 0
71
- next if e.empty?
72
-
73
- # Unable to deliver message to: <kijitora@example.org>
74
- # Delivery failed for the following reason:
75
- # Server mx22.example.org[192.0.2.222] failed with: 550 <kijitora@example.org> No such user here
76
- #
77
- # This has been a permanent failure. No further delivery attempts will be made.
78
- v = dscontents[-1]
79
-
80
- if cv = e.match(/\AUnable to deliver message to: [<]([^ ]+[@][^ ]+)[>]\z/)
81
- # Unable to deliver message to: <kijitora@example.org>
82
- if v['recipient']
83
- # There are multiple recipient addresses in the message body.
84
- dscontents << Sisimai::Lhost.DELIVERYSTATUS
85
- v = dscontents[-1]
86
- end
87
- v['recipient'] = cv[1]
88
- recipients += 1
70
+ # Error message
71
+ if e == StartingOf[:error][0]
72
+ # Delivery failed for the following reason:
73
+ v['diagnosis'] = e
89
74
  else
90
- # Error message
91
- if e == StartingOf[:error][0]
92
- # Delivery failed for the following reason:
93
- v['diagnosis'] = e
94
- else
95
- # Detect error message
96
- next if e.empty?
97
- next if v['diagnosis'].nil? || v['diagnosis'].empty?
98
- next if e.start_with?('-')
75
+ # Detect error message
76
+ next if e.empty?
77
+ next if v['diagnosis'].nil? || v['diagnosis'].empty?
78
+ next if e.start_with?('-')
99
79
 
100
- # Server mx22.example.org[192.0.2.222] failed with: 550 <kijitora@example.org> No such user here
101
- v['diagnosis'] << ' ' << e
102
- end
80
+ # Server mx22.example.org[192.0.2.222] failed with: 550 <kijitora@example.org> No such user here
81
+ v['diagnosis'] << ' ' << e
103
82
  end
104
83
  end
105
84
  end
@@ -111,8 +90,7 @@ module Sisimai::Lhost
111
90
  e.each_key { |a| e[a] ||= '' }
112
91
  end
113
92
 
114
- rfc822part = Sisimai::RFC5322.weedout(rfc822list)
115
- return { 'ds' => dscontents, 'rfc822' => rfc822part }
93
+ return { 'ds' => dscontents, 'rfc822' => emailsteak[1] }
116
94
  end
117
95
 
118
96
  end
@@ -8,6 +8,7 @@ module Sisimai::Lhost
8
8
  require 'sisimai/lhost'
9
9
 
10
10
  Indicators = Sisimai::Lhost.INDICATORS
11
+ ReBackbone = %r/^[ \t]*[+]+[ \t]*/.freeze
11
12
  StartingOf = {
12
13
  message: ['Your message:'],
13
14
  error: ['Could not be delivered because of'],
@@ -33,9 +34,8 @@ module Sisimai::Lhost
33
34
  return nil unless mhead['subject'].start_with?('Undeliverable Mail: "')
34
35
 
35
36
  dscontents = [Sisimai::Lhost.DELIVERYSTATUS]
36
- hasdivided = mbody.split("\n")
37
- rfc822list = [] # (Array) Each line in message/rfc822 part string
38
- blanklines = 0 # (Integer) The number of blank lines
37
+ emailsteak = Sisimai::RFC5322.fillet(mbody, ReBackbone)
38
+ bodyslices = emailsteak[0].split("\n")
39
39
  readcursor = 0 # (Integer) Points the current cursor position
40
40
  recipients = 0 # (Integer) The number of 'Final-Recipient' header
41
41
  endoferror = false # (Boolean) Flag for the end of error message
@@ -50,99 +50,77 @@ module Sisimai::Lhost
50
50
  regularexp = %r/\A[ \t]*[+]+[ \t]*\z/
51
51
  end
52
52
 
53
- while e = hasdivided.shift do
53
+ while e = bodyslices.shift do
54
+ # Read error messages and delivery status lines from the head of the email
55
+ # to the previous line of the beginning of the original message.
54
56
  if readcursor == 0
55
57
  # Beginning of the bounce message or delivery status part
56
- if e == StartingOf[:message][0]
57
- readcursor |= Indicators[:deliverystatus]
58
- next
59
- end
60
- end
61
-
62
- if (readcursor & Indicators[:'message-rfc822']) == 0
63
- # Beginning of the original message part
64
- if e =~ regularexp
65
- readcursor |= Indicators[:'message-rfc822']
66
- next
67
- end
58
+ readcursor |= Indicators[:deliverystatus] if e == StartingOf[:message][0]
68
59
  end
69
-
70
- if readcursor & Indicators[:'message-rfc822'] > 0
71
- # Inside of the original message part
72
- if e.empty?
73
- blanklines += 1
74
- break if blanklines > 1
75
- next
76
- end
77
- rfc822list << e
78
- else
79
- # Error message part
80
- next if (readcursor & Indicators[:deliverystatus]) == 0
81
- break if e =~ regularexp
82
-
83
- # Your message:
84
- # From: originalsender@example.com
85
- # Subject: IIdentifica蟾ス驕俳
86
- #
87
- # Could not be delivered because of
88
- #
89
- # 550 5.1.1 User unknown
90
- #
60
+ next if (readcursor & Indicators[:deliverystatus]) == 0
61
+
62
+ # Your message:
63
+ # From: originalsender@example.com
64
+ # Subject: IIdentifica蟾ス驕俳
65
+ #
66
+ # Could not be delivered because of
67
+ #
68
+ # 550 5.1.1 User unknown
69
+ #
70
+ # The following recipients were affected:
71
+ # dummyuser@blabla.xxxxxxxxxxxx.com
72
+ v = dscontents[-1]
73
+
74
+ if cv = e.match(/\A[ ]{4}([^ ]+[@][^ ]+)\z/)
91
75
  # The following recipients were affected:
92
76
  # dummyuser@blabla.xxxxxxxxxxxx.com
93
- v = dscontents[-1]
94
-
95
- if cv = e.match(/\A[ ]{4}([^ ]+[@][^ ]+)\z/)
96
- # The following recipients were affected:
97
- # dummyuser@blabla.xxxxxxxxxxxx.com
98
- if v['recipient']
99
- # There are multiple recipient addresses in the message body.
100
- dscontents << Sisimai::Lhost.DELIVERYSTATUS
101
- v = dscontents[-1]
102
- end
103
- v['recipient'] = cv[1]
104
- recipients += 1
77
+ if v['recipient']
78
+ # There are multiple recipient addresses in the message body.
79
+ dscontents << Sisimai::Lhost.DELIVERYSTATUS
80
+ v = dscontents[-1]
81
+ end
82
+ v['recipient'] = cv[1]
83
+ recipients += 1
84
+ else
85
+ # Get error message lines
86
+ if e == StartingOf[:error][0]
87
+ # Could not be delivered because of
88
+ #
89
+ # 550 5.1.1 User unknown
90
+ v['diagnosis'] = e
91
+
92
+ elsif !v['diagnosis'].to_s.empty? && endoferror == false
93
+ # Append error messages
94
+ endoferror = true if e.start_with?(StartingOf[:rcpts][0])
95
+ next if endoferror
96
+ v['diagnosis'] << ' ' << e
105
97
  else
106
- # Get error message lines
107
- if e == StartingOf[:error][0]
108
- # Could not be delivered because of
109
- #
110
- # 550 5.1.1 User unknown
111
- v['diagnosis'] = e
112
-
113
- elsif !v['diagnosis'].to_s.empty? && endoferror == false
114
- # Append error messages
115
- endoferror = true if e.start_with?(StartingOf[:rcpts][0])
116
- next if endoferror
117
- v['diagnosis'] << ' ' << e
118
- else
119
- # Additional Information
120
- # ======================
98
+ # Additional Information
99
+ # ======================
100
+ # Original Sender: <originalsender@example.com>
101
+ # Sender-MTA: <10.11.12.13>
102
+ # Remote-MTA: <10.0.0.1>
103
+ # Reporting-MTA: <relay.xxxxxxxxxxxx.com>
104
+ # MessageName: <B549996730000.000000000001.0003.mml>
105
+ # Last-Attempt-Date: <16:21:07 seg, 22 Dezembro 2014>
106
+ if cv = e.match(/\AOriginal Sender:[ \t]+[<](.+)[>]\z/)
121
107
  # Original Sender: <originalsender@example.com>
108
+ # Use this line instead of "From" header of the original
109
+ # message.
110
+ emailsteak[1] << ('From: ' << cv[1] << "\n")
111
+
112
+ elsif cv = e.match(/\ASender-MTA:[ \t]+[<](.+)[>]\z/)
122
113
  # Sender-MTA: <10.11.12.13>
123
- # Remote-MTA: <10.0.0.1>
114
+ v['lhost'] = cv[1]
115
+
116
+ elsif cv = e.match(/\AReporting-MTA:[ \t]+[<](.+)[>]\z/)
124
117
  # Reporting-MTA: <relay.xxxxxxxxxxxx.com>
125
- # MessageName: <B549996730000.000000000001.0003.mml>
126
- # Last-Attempt-Date: <16:21:07 seg, 22 Dezembro 2014>
127
- if cv = e.match(/\AOriginal Sender:[ \t]+[<](.+)[>]\z/)
128
- # Original Sender: <originalsender@example.com>
129
- # Use this line instead of "From" header of the original
130
- # message.
131
- rfc822list << ('From: ' << cv[1])
132
-
133
- elsif cv = e.match(/\ASender-MTA:[ \t]+[<](.+)[>]\z/)
134
- # Sender-MTA: <10.11.12.13>
135
- v['lhost'] = cv[1]
136
-
137
- elsif cv = e.match(/\AReporting-MTA:[ \t]+[<](.+)[>]\z/)
138
- # Reporting-MTA: <relay.xxxxxxxxxxxx.com>
139
- v['rhost'] = cv[1]
140
-
141
- elsif cv = e.match(/\A\s+(From|Subject):\s*(.+)\z/)
142
- # From: originalsender@example.com
143
- # Subject: ...
144
- rfc822list << sprintf("%s: %s", cv[1], cv[2])
145
- end
118
+ v['rhost'] = cv[1]
119
+
120
+ elsif cv = e.match(/\A\s+(From|Subject):\s*(.+)\z/)
121
+ # From: originalsender@example.com
122
+ # Subject: ...
123
+ emailsteak[1] << sprintf("%s: %s\n", cv[1], cv[2])
146
124
  end
147
125
  end
148
126
  end
@@ -155,8 +133,7 @@ module Sisimai::Lhost
155
133
  e.each_key { |a| e[a] ||= '' }
156
134
  end
157
135
 
158
- rfc822part = Sisimai::RFC5322.weedout(rfc822list)
159
- return { 'ds' => dscontents, 'rfc822' => rfc822part }
136
+ return { 'ds' => dscontents, 'rfc822' => emailsteak[1] }
160
137
  end
161
138
 
162
139
  end