sisimai 4.22.2 → 4.22.3

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 (86) hide show
  1. checksums.yaml +4 -4
  2. data/ANALYTICAL-PRECISION +24 -23
  3. data/ChangeLog.md +39 -2
  4. data/README-JA.md +10 -10
  5. data/README.md +10 -10
  6. data/lib/sisimai.rb +0 -1
  7. data/lib/sisimai/bite/email.rb +1 -1
  8. data/lib/sisimai/bite/email/amazonses.rb +1 -2
  9. data/lib/sisimai/bite/email/exim.rb +46 -8
  10. data/lib/sisimai/bite/email/fml.rb +170 -0
  11. data/lib/sisimai/bite/email/imailserver.rb +1 -1
  12. data/lib/sisimai/bite/email/messagelabs.rb +6 -1
  13. data/lib/sisimai/bite/email/office365.rb +0 -1
  14. data/lib/sisimai/data.rb +34 -12
  15. data/lib/sisimai/datetime.rb +10 -4
  16. data/lib/sisimai/reason.rb +70 -55
  17. data/lib/sisimai/reason/blocked.rb +91 -21
  18. data/lib/sisimai/reason/expired.rb +7 -3
  19. data/lib/sisimai/reason/filtered.rb +1 -0
  20. data/lib/sisimai/reason/hostunknown.rb +9 -5
  21. data/lib/sisimai/reason/mailboxfull.rb +17 -9
  22. data/lib/sisimai/reason/mailererror.rb +5 -4
  23. data/lib/sisimai/reason/mesgtoobig.rb +2 -0
  24. data/lib/sisimai/reason/networkerror.rb +11 -3
  25. data/lib/sisimai/reason/norelaying.rb +5 -2
  26. data/lib/sisimai/reason/policyviolation.rb +9 -2
  27. data/lib/sisimai/reason/rejected.rb +41 -10
  28. data/lib/sisimai/reason/securityerror.rb +2 -0
  29. data/lib/sisimai/reason/spamdetected.rb +37 -20
  30. data/lib/sisimai/reason/suspend.rb +10 -4
  31. data/lib/sisimai/reason/systemerror.rb +1 -0
  32. data/lib/sisimai/reason/toomanyconn.rb +4 -0
  33. data/lib/sisimai/reason/userunknown.rb +40 -20
  34. data/lib/sisimai/reason/vacation.rb +20 -1
  35. data/lib/sisimai/reason/virusdetected.rb +3 -1
  36. data/lib/sisimai/rfc3464.rb +3 -4
  37. data/lib/sisimai/rfc3834.rb +37 -6
  38. data/lib/sisimai/rhost.rb +2 -1
  39. data/lib/sisimai/rhost/exchangeonline.rb +29 -0
  40. data/lib/sisimai/rhost/franceptt.rb +58 -0
  41. data/lib/sisimai/smtp/status.rb +1 -0
  42. data/lib/sisimai/version.rb +1 -1
  43. data/set-of-emails/jsonobj/json-amazonses-06.json +1 -0
  44. data/set-of-emails/maildir/bsd/email-exim-31.eml +39 -0
  45. data/set-of-emails/maildir/bsd/email-exim-32.eml +42 -0
  46. data/set-of-emails/maildir/bsd/email-exim-33.eml +42 -0
  47. data/set-of-emails/maildir/bsd/email-exim-34.eml +41 -0
  48. data/set-of-emails/maildir/bsd/email-exim-35.eml +41 -0
  49. data/set-of-emails/maildir/bsd/email-exim-36.eml +41 -0
  50. data/set-of-emails/maildir/bsd/email-exim-37.eml +41 -0
  51. data/set-of-emails/maildir/bsd/email-exim-38.eml +32 -0
  52. data/set-of-emails/maildir/bsd/email-exim-39.eml +47 -0
  53. data/set-of-emails/maildir/bsd/email-exim-40.eml +41 -0
  54. data/set-of-emails/maildir/bsd/email-exim-41.eml +32 -0
  55. data/set-of-emails/maildir/bsd/email-exim-42.eml +41 -0
  56. data/set-of-emails/maildir/bsd/email-exim-43.eml +60 -0
  57. data/set-of-emails/maildir/bsd/email-exim-44.eml +64 -0
  58. data/set-of-emails/maildir/bsd/email-exim-45.eml +43 -0
  59. data/set-of-emails/maildir/bsd/email-exim-46.eml +41 -0
  60. data/set-of-emails/maildir/bsd/email-exim-47.eml +42 -0
  61. data/set-of-emails/maildir/bsd/email-exim-48.eml +59 -0
  62. data/set-of-emails/maildir/bsd/email-exim-49.eml +59 -0
  63. data/set-of-emails/maildir/bsd/email-exim-50.eml +41 -0
  64. data/set-of-emails/maildir/bsd/email-exim-51.eml +41 -0
  65. data/set-of-emails/maildir/bsd/email-exim-52.eml +34 -0
  66. data/set-of-emails/maildir/bsd/email-exim-53.eml +48 -0
  67. data/set-of-emails/maildir/bsd/email-exim-54.eml +40 -0
  68. data/set-of-emails/maildir/bsd/email-exim-55.eml +38 -0
  69. data/set-of-emails/maildir/bsd/email-exim-56.eml +40 -0
  70. data/set-of-emails/maildir/bsd/email-exim-57.eml +39 -0
  71. data/set-of-emails/maildir/bsd/email-exim-58.eml +43 -0
  72. data/set-of-emails/maildir/bsd/email-fml-01.eml +70 -0
  73. data/set-of-emails/maildir/bsd/email-fml-02.eml +44 -0
  74. data/set-of-emails/maildir/bsd/email-office365-03.eml +117 -0
  75. data/set-of-emails/maildir/bsd/email-postfix-31.eml +94 -0
  76. data/set-of-emails/maildir/bsd/email-sendmail-45.eml +102 -0
  77. data/set-of-emails/maildir/bsd/email-sendmail-46.eml +103 -0
  78. data/set-of-emails/maildir/bsd/email-sendmail-47.eml +102 -0
  79. data/set-of-emails/maildir/bsd/email-sendmail-48.eml +101 -0
  80. data/set-of-emails/maildir/bsd/rfc3464-33.eml +38 -0
  81. data/set-of-emails/maildir/bsd/rfc3464-34.eml +53 -0
  82. data/set-of-emails/maildir/bsd/rhost-exchange-online-02.eml +89 -0
  83. data/set-of-emails/maildir/bsd/rhost-exchange-online-03.eml +205 -0
  84. data/set-of-emails/maildir/bsd/rhost-franceptt-01.eml +102 -0
  85. data/set-of-emails/maildir/bsd/rhost-franceptt-02.eml +103 -0
  86. metadata +47 -2
@@ -20,18 +20,24 @@ module Sisimai
20
20
  def match(argv1)
21
21
  return nil unless argv1
22
22
  regex = %r{(?>
23
- invalid/inactive[ ]user
24
- # http://service.mail.qq.com/cgi-bin/help?subtype=1&&id=20022&&no=1000742
23
+ Boite[ ]du[ ]destinataire[ ]archivee.+[A-Z]{3}.+420
25
24
  |email[ ]account[ ]that[ ]you[ ]tried[ ]to[ ]reach[ ]is[ ]disabled
25
+ |invalid/inactive[ ]user
26
+ # http://service.mail.qq.com/cgi-bin/help?subtype=1&&id=20022&&no=1000742
26
27
  |is[ ]a[ ]deactivated[ ]mailbox
27
28
  |mailbox[ ](?:
28
29
  currently[ ]suspended
29
30
  |unavailable[ ]or[ ]access[ ]denied
30
31
  )
31
- |user[ ]suspended # http://mail.163.com/help/help_spam_16.htm
32
- |recipient[ ]suspend[ ]the[ ]service
32
+ |recipient[ ](?:
33
+ rejected:[ ]Temporarily[ ]inactive
34
+ |suspend[ ]the[ ]service
35
+ )
33
36
  |sorry[ ]your[ ]message[ ]to[ ].+[ ]cannot[ ]be[ ]delivered[.][ ]this[ ]
34
37
  account[ ]has[ ]been[ ]disabled[ ]or[ ]discontinued
38
+ |The[ ]domain[ ].+[ ]is[ ]currently[ ]suspended
39
+ |User[ ].+[ ]temporary[ ]locked
40
+ |user[ ]suspended # http://mail.163.com/help/help_spam_16.htm
35
41
  |vdelivermail:[ ]account[ ]is[ ]locked[ ]email[ ]bounced
36
42
  )
37
43
  }ix
@@ -25,6 +25,7 @@ module Sisimai
25
25
  return nil unless argv1
26
26
  regex = %r{(?>
27
27
  can[']t[ ]create[ ]user[ ]output[ ]file
28
+ |Could[ ]not[ ]load[ ]DRD[ ]for[ ]domain
28
29
  |Internal[ ](?:
29
30
  error[ ]reading[ ]data # Microsoft
30
31
  |server[ ]error:[ ]Operation[ ]now[ ]in[ ]progress # Microsoft
@@ -26,6 +26,7 @@ module Sisimai
26
26
  regex = %r{(?>
27
27
  All[ ]available[ ]IPs[ ]are[ ]at[ ]maximum[ ]connection[ ]limit # SendGrid
28
28
  |connection[ ]rate[ ]limit[ ]exceeded
29
+ |domain[ ].+[ ]has[ ]exceeded[ ]the[ ]max[ ]emails[ ]per[ ]hour[ ].+[ ]allowed
29
30
  |no[ ]IPs[ ]available[ ][-][ ].+[ ]exceeds[ ]per[-]domain[ ]connection[ ]limit[ ]for
30
31
  |Throttling[ ]failure:[ ](?:
31
32
  Daily[ ]message[ ]quota[ ]exceeded
@@ -35,8 +36,11 @@ module Sisimai
35
36
  connections
36
37
  |connections[ ]from[ ]your[ ]host[.] # Microsoft
37
38
  |concurrent[ ]SMTP[ ]connections # Microsoft
39
+ |errors[ ]from[ ]your[ ]IP # Free.fr
38
40
  |SMTP[ ]sessions[ ]for[ ]this[ ]host # Sendmail(daemon.c)
39
41
  )
42
+ |Trop[ ]de[ ]connexions,[ ].+[A-Z]{3}.+104
43
+ |We[ ]have[ ]already[ ]made[ ]numerous[ ]attempts[ ]to[ ]deliver[ ]this[ ]message
40
44
  )
41
45
  }ix
42
46
 
@@ -31,65 +31,83 @@ module Sisimai
31
31
  .+[ ]user[ ]unknown
32
32
  |[#]5[.]1[.]1[ ]bad[ ]address
33
33
  |[<].+[>][ ]not[ ]found
34
- |address[ ]does[ ]not[ ]exist
35
- |address[ ]unknown
34
+ |[<].+[@].+[>][.][.][.][ ]Blocked[ ]by[ ]
35
+ |5[.]0[.]0[.][ ]Mail[ ]rejected[.]
36
+ |5[.]1[.]0[ ]Address[ ]rejected[.]
37
+ |Adresse[ ]d[ ]au[ ]moins[ ]un[ ]destinataire[ ]invalide.+[A-Z]{3}.+(?:416|418)
38
+ |address[ ](?:does[ ]not[ ]exist|unknown)
36
39
  |archived[ ]recipient
37
40
  |BAD[-_ ]RECIPIENT
38
41
  |can[']t[ ]accept[ ]user
39
- |destination[ ]addresses[ ]were[ ]unknown
40
- |destination[ ]server[ ]rejected[ ]recipients
41
- |email[ ]address[ ]does[ ]not[ ]exist
42
+ |destination[ ](?:
43
+ addresses[ ]were[ ]unknown
44
+ |server[ ]rejected[ ]recipients
45
+ )
46
+ |email[ ]address[ ](?:does[ ]not[ ]exist|could[ ]not[ ]be[ ]found)
42
47
  |invalid[ ](?:
43
48
  address
49
+ |mailbox:
44
50
  |mailbox[ ]path
45
- |recipient # Linkedin
51
+ |recipient
46
52
  )
47
53
  |is[ ]not[ ](?:
48
54
  a[ ]known[ ]user
55
+ |a[ ]valid[ ]mailbox
49
56
  |an[ ]active[ ]address[ ]at[ ]this[ ]host
50
57
  )
51
58
  |mailbox[ ](?:
52
- not[ ]present
53
- |not[ ]found
59
+ .+[ ]does[ ]not[ ]exist
60
+ |.+[@].+[ ]unavailable
61
+ |invalid
62
+ |is[ ](?:inactive|unavailable)
63
+ |not[ ](?:present|found)
54
64
  |unavailable
55
65
  )
56
66
  |no[ ](?:
57
- account[ ]by[ ]that[ ]name[ ]here
67
+ [ ].+[ ]in[ ]name[ ]directory
68
+ |account[ ]by[ ]that[ ]name[ ]here
69
+ |existe[ ](?:dicha[ ]persona|ese[ ]usuario[ ])
58
70
  |mail[ ]box[ ]available[ ]for[ ]this[ ]user
59
- |mailbox[ ]found
71
+ |mailbox[ ](?:
72
+ by[ ]that[ ]name[ ]is[ ]currently[ ]available
73
+ |found
74
+ )
60
75
  |matches[ ]to[ ]nameserver[ ]query
61
76
  |such[ ](?:
62
- mailbox
77
+ address[ ]here
78
+ |mailbox
63
79
  |person[ ]at[ ]this[ ]address
64
80
  |recipient
65
81
  |user(?:[ ]here)?
66
82
  )
67
- |[ ].+[ ]in[ ]name[ ]directory
83
+ |thank[ ]you[ ]rejected:[ ]Account[ ]Unavailable:
68
84
  |valid[ ]recipients[,][ ]bye # Microsoft
69
85
  )
70
86
  |non[- ]?existent[ ]user
71
87
  |not[ ](?:
72
88
  a[ ]valid[ ]user[ ]here
73
89
  |a[ ]local[ ]address
90
+ |email[ ]addresses
74
91
  )
75
92
  |rcpt[ ][<].+[>][ ]does[ ]not[ ]exist
76
- |recipient[ ](?:
93
+ |rece?ipient[ ](?:
77
94
  .+[ ]was[ ]not[ ]found[ ]in
78
95
  |address[ ]rejected:[ ](?:
79
- invalid[ ]user
96
+ Access[ ]denied
97
+ |invalid[ ]user
80
98
  |user[ ].+[ ]does[ ]not[ ]exist
81
99
  |user[ ]unknown[ ]in[ ].+[ ]table
82
100
  |unknown[ ]user
83
101
  )
84
102
  |does[ ]not[ ]exist(?:[ ]on[ ]this[ ]system)?
85
103
  |is[ ]not[ ]local
86
- |not[ ]found
87
- |not[ ]OK
104
+ |not[ ](?:exist|found|OK)
88
105
  |unknown
89
106
  )
90
107
  |requested[ ]action[ ]not[ ]taken:[ ]mailbox[ ]unavailable
91
- |RESOLVER[.]ADR[.]RecipNotFound # Microsoft
108
+ |RESOLVER[.]ADR[.]Recip(?:ient)NotFound
92
109
  |said:[ ]550[-[ ]]5[.]1[.]1[ ].+[ ]user[ ]unknown[ ]
110
+ |SMTP[ ]error[ ]from[ ]remote[ ]mail[ ]server[ ]after[ ]end[ ]of[ ]data:[ ]553.+does[ ]not[ ]exist
93
111
  |sorry,[ ](?:
94
112
  user[ ]unknown
95
113
  |badrcptto
@@ -100,9 +118,11 @@ module Sisimai
100
118
  |following[ ]recipients[ ]was[ ]undeliverable
101
119
  |user[']s[ ]email[ ]name[ ]is[ ]not[ ]found
102
120
  )
121
+ |There[ ]is[ ]no[ ]one[ ]at[ ]this[ ]address
103
122
  |this[ ](?:
104
123
  address[ ]no[ ]longer[ ]accepts[ ]mail
105
124
  |email[ ]address[ ]is[ ]wrong[ ]or[ ]no[ ]longer[ ]valid
125
+ |spectator[ ]does[ ]not[ ]exist
106
126
  |user[ ]doesn[']?t[ ]have[ ]a[ ].+[ ]account
107
127
  )
108
128
  |unknown[ ](?:
@@ -117,11 +137,11 @@ module Sisimai
117
137
  |.+[ ]does[ ]not[ ]exist
118
138
  |does[ ]not[ ]exist
119
139
  |missing[ ]home[ ]directory
120
- |not[ ]found # 550 User not found. See http://mail.bigmir.net/err/2/
121
- |not[ ]known
140
+ |not[ ](?:active|found|known)
122
141
  |unknown
123
142
  )
124
143
  |vdeliver:[ ]invalid[ ]or[ ]unknown[ ]virtual[ ]user
144
+ |your[ ]envelope[ ]recipient[ ]is[ ]in[ ]my[ ]badrcptto[ ]list
125
145
  )
126
146
  }ix
127
147
 
@@ -140,7 +160,7 @@ module Sisimai
140
160
  return true if argvs.reason == Sisimai::Reason::UserUnknown.text
141
161
 
142
162
  require 'sisimai/smtp/status'
143
- prematches = %w|NoRelaying Blocked MailboxFull HasMoved|
163
+ prematches = %w|NoRelaying Blocked MailboxFull HasMoved Blocked Rejected|
144
164
  matchother = false
145
165
  statuscode = argvs.deliverystatus || ''
146
166
  diagnostic = argvs.diagnosticcode || ''
@@ -9,7 +9,26 @@ module Sisimai
9
9
  def description
10
10
  return 'Email replied automatically due to a recipient is out of office'
11
11
  end
12
- def match; return nil; end
12
+
13
+ # Try to match that the given text and regular expressions
14
+ # @param [String] argv1 String to be matched with regular expressions
15
+ # @return [True,False] false: Did not match
16
+ # true: Matched
17
+ def match(argv1)
18
+ return nil unless argv1
19
+ regex = %r{(?>
20
+ I[ ]am[ ](?:
21
+ away[ ](?:on[ ]vacation|until)
22
+ |out[ ]of[ ]the[ ]office
23
+ )
24
+ |I[ ]will[ ]be[ ]traveling[ ]for[ ]work[ ]on
25
+ )
26
+ }ix
27
+
28
+ return true if argv1 =~ regex
29
+ return false
30
+ end
31
+
13
32
  def true(*); return nil; end
14
33
  end
15
34
  end
@@ -29,7 +29,9 @@ module Sisimai
29
29
  def match(argv1)
30
30
  return nil unless argv1
31
31
  regex = %r{(?>
32
- the[ ]message[ ]was[ ]rejected[ ]because[ ]it[ ]contains[ ]prohibited[ ]virus[ ]or[ ]spam[ ]content
32
+ it[ ]has[ ]a[ ]potentially[ ]executable[ ]attachment
33
+ |the[ ]message[ ]was[ ]rejected[ ]because[ ]it[ ]contains[ ]prohibited[ ]virus[ ]or[ ]spam[ ]content
34
+ |This[ ]form[ ]of[ ]attachment[ ]has[ ]been[ ]used[ ]by[ ]recent[ ]viruses[ ]or[ ]other[ ]malware
33
35
  |Your[ ]message[ ]was[ ]infected[ ]with[ ]a[ ]virus
34
36
  )
35
37
  }ix
@@ -68,7 +68,7 @@ module Sisimai
68
68
  require 'sisimai/address'
69
69
 
70
70
  dscontents = [Sisimai::Bite.DELIVERYSTATUS]
71
- hasdivided = mbody.split("\n")
71
+ hasdivided = mbody.scrub('?').split("\n")
72
72
  havepassed = ['']
73
73
  scannedset = Sisimai::MDA.scan(mhead, mbody)
74
74
  rfc822list = [] # (Array) Each line in message/rfc822 part string
@@ -372,7 +372,6 @@ module Sisimai
372
372
  |Error-for:[ ]+
373
373
  |Failed[ ]Recipient:[ ]
374
374
  |Failed[ ]to[ ]deliver[ ]to[ ]
375
- |generated[ ]from[ ]
376
375
  |Intended[ ]recipient:[ ]
377
376
  |Mailbox[ ]is[ ]full:[ ]
378
377
  |RCPT[ ]To:
@@ -414,7 +413,7 @@ module Sisimai
414
413
  b['agent'] = self.smtpagent + '::Fallback'
415
414
  recipients += 1
416
415
 
417
- elsif cv = e.match(/[(]expanded[ ]from:[ ]([^@]+[@][^@]+)[)]/)
416
+ elsif cv = e.match(/[(](?:expanded|generated)[ ]from:?[ ]([^@]+[@][^@]+)[)]/)
418
417
  # (expanded from: neko@example.jp)
419
418
  b['alias'] = Sisimai::Address.s3s4(cv[1])
420
419
  end
@@ -430,7 +429,7 @@ module Sisimai
430
429
  rfc822list.each do |e|
431
430
  # Check To: header in the original message
432
431
  next unless cv = e.match(/\ATo:\s*(.+)\z/)
433
- r = Sisimai::Address.find(cv[1], true)
432
+ r = Sisimai::Address.find(cv[1], true) || []
434
433
  next if r.empty?
435
434
 
436
435
  if dscontents.size == recipients
@@ -10,13 +10,18 @@ module Sisimai
10
10
  # https://msdn.microsoft.com/en-us/library/ee219609(v=exchg.80).aspx
11
11
  :'x-auto-response-suppress' => %r/(?:OOF|AutoReply)/i,
12
12
  :'precedence' => %r/\Aauto_reply\z/,
13
- :'subject' => %r/\A(?:
13
+ :'subject' => %r/\A(?>
14
14
  Auto:
15
- |Out[ ]of[ ]Office:
15
+ |Auto[ ]Response:
16
+ |Automatic[ ]reply:
17
+ |Out[ ]of[ ](?:the[ ])*Office:
16
18
  )
17
19
  /xi,
18
20
  }.freeze
19
- Re1 = { :endof => %r/\A__END_OF_EMAIL_MESSAGE__\z/ }.freeze
21
+ Re1 = {
22
+ :boundary => %r/\A__SISIMAI_PSEUDO_BOUNDARY__\z/,
23
+ :endof => %r/\A__END_OF_EMAIL_MESSAGE__\z/
24
+ }
20
25
  Re2 = {
21
26
  :subject => %r/(?:
22
27
  SECURITY[ ]information[ ]for # sudo
@@ -26,6 +31,14 @@ module Sisimai
26
31
  :from => %r/(?:root|postmaster|mailer-daemon)[@]/i,
27
32
  :to => %r/root[@]/,
28
33
  }.freeze
34
+ ReV = %r{\A(?>
35
+ (?:.+?)?Re:
36
+ |Auto(?:[ ]Response):
37
+ |Automatic[ ]reply:
38
+ |Out[ ]of[ ]Office:
39
+ )
40
+ [ ]*(.+)\z
41
+ }xi
29
42
 
30
43
  def description; 'Detector for auto replied message'; end
31
44
  def smtpagent; 'RFC3834'; end
@@ -84,11 +97,13 @@ module Sisimai
84
97
  require 'sisimai/address'
85
98
 
86
99
  dscontents = [Sisimai::Bite.DELIVERYSTATUS]
87
- hasdivided = mbody.split("\n")
100
+ hasdivided = mbody.scrub('?').split("\n")
101
+ rfc822part = '' # (String) message/rfc822-headers part
88
102
  recipients = 0 # (Integer) The number of 'Final-Recipient' header
89
103
  maxmsgline = 5 # (Integer) Max message length(lines)
90
104
  haveloaded = 0 # (Integer) The number of lines loaded from message body
91
105
  blanklines = 0 # (Integer) Counter for countinuous blank lines
106
+ countuntil = 1 # (Integer) Maximum value of blank lines in the body part
92
107
  v = dscontents[-1]
93
108
 
94
109
  # RECIPIENT_ADDRESS
@@ -107,16 +122,27 @@ module Sisimai
107
122
  end
108
123
  return nil unless recipients > 0
109
124
 
125
+ if mhead['content-type']
126
+ # Get the boundary string and set regular expression for matching with
127
+ # the boundary string.
128
+ require 'sisimai/mime'
129
+ b0 = Sisimai::MIME.boundary(mhead['content-type'], 0)
130
+ Re1[:boundary] = %r/\A\Q#{b0}\E\z/ unless b0.empty?
131
+ end
132
+
110
133
  # BODY_PARSER: Get vacation message
111
134
  hasdivided.each do |e|
112
135
  # Read the first 5 lines except a blank line
136
+ countuntil += 1 if e =~ Re1[:boundary]
137
+
113
138
  unless e.size > 0
114
139
  # Check a blank line
115
140
  blanklines += 1
116
- break if blanklines > 1
141
+ break if blanklines > countuntil
117
142
  next
118
143
  end
119
144
  next unless e =~ / /
145
+ next if e =~ /\AContent-(?:Type|Transfer)/
120
146
 
121
147
  v['diagnosis'] ||= ''
122
148
  v['diagnosis'] += e + ' '
@@ -133,7 +159,12 @@ module Sisimai
133
159
  v['status'] = ''
134
160
 
135
161
  v.each_key { |a| v[a] ||= '' }
136
- return { 'ds' => dscontents, 'rfc822' => '' }
162
+
163
+ if cv = mhead['subject'].match(ReV)
164
+ # Get the Subject header from the original message
165
+ rfc822part = sprintf("Subject: %s\n", cv[1])
166
+ end
167
+ return { 'ds' => dscontents, 'rfc822' => rfc822part }
137
168
  end
138
169
 
139
170
  end
data/lib/sisimai/rhost.rb CHANGED
@@ -8,8 +8,9 @@ module Sisimai
8
8
  # Imported from p5-Sisimail/lib/Sisimai/Rhost.pm
9
9
  RhostClass = {
10
10
  %r/\Aaspmx[.]l[.]google[.]com\z/ => 'GoogleApps',
11
- %r/[.]protection[.]outlook[.]com\z/ => 'ExchangeOnline',
11
+ %r/[.](?:prod|protection)[.]outlook[.]com\z/ => 'ExchangeOnline',
12
12
  %r/\A(?:smtp|mailstore1)[.]secureserver[.]net\z/ => 'GoDaddy',
13
+ %r/\b(?:laposte[.]net|orange[.]fr)\z/ => 'FrancePTT',
13
14
  }.freeze
14
15
 
15
16
  # Retrun the list of remote hosts Sisimai support
@@ -128,6 +128,12 @@ module Sisimai
128
128
  :regexp => %r/(?:Invalid[ ]arguments|Routing[ ]loop[ ]detected)/x,
129
129
  },
130
130
  ],
131
+ %r/\A5[.]4[.]14\z/ => [
132
+ {
133
+ :reason => 'networkerror',
134
+ :regexp => %r/Hop[ ]count[ ]exceeded/x
135
+ },
136
+ ],
131
137
  %r/\A5[.]5[.]2\z/ => [
132
138
  {
133
139
  :reason => 'syntaxerror',
@@ -239,6 +245,18 @@ module Sisimai
239
245
  },
240
246
  ],
241
247
  }.freeze
248
+ MesgTable = {
249
+ # Copied and converted from Sisimai::Bite::Email::Exchange2007
250
+ :expired => %r/QUEUE[.]Expired/,
251
+ :hostunknown => %r/SMTPSEND[.]DNS[.]NonExistentDomain/,
252
+ :mesgtoobig => %r/RESOLVER[.]RST[.]Recip(?:ient)?SizeLimit/,
253
+ :networkerror => %r/SMTPSEND[.]DNS[.]MxLoopback/,
254
+ :rejected => %r/RESOLVER[.]RST[.]NotAuthorized/,
255
+ :securityerror => %r/RESOLVER[.]RST[.]AuthRequired/,
256
+ :systemerror => %r/RESOLVER[.]ADR[.](?:Ambiguous|BadPrimary|InvalidInSmtp)/,
257
+ :toomanyconn => %r/RESOLVER[.]ADR[.]Recip(?:ient)?Limit/,
258
+ :userunknown => %r/RESOLVER[.]ADR[.](?:Ex)?Recip(?:ient)?NotFound/,
259
+ }.freeze
242
260
 
243
261
  # Detect bounce reason from Exchange Online
244
262
  # @param [Sisimai::Data] argvs Parsed email object
@@ -263,6 +281,17 @@ module Sisimai
263
281
  end
264
282
  end
265
283
 
284
+ if reasontext.empty?
285
+ # D.S.N. included in the error message did not matched with any key
286
+ # in CodeTable
287
+ MesgTable.each_key do |e|
288
+ # Try to match with error messages defined in MesgTable
289
+ next unless statusmesg =~ MesgTable[e]
290
+ reasontext = e.to_s
291
+ break
292
+ end
293
+ end
294
+
266
295
  return reasontext
267
296
  end
268
297
 
@@ -0,0 +1,58 @@
1
+ module Sisimai
2
+ module Rhost
3
+ # Sisimai::Rhost detects the bounce reason from the content of Sisimai::Data
4
+ # object as an argument of get() method when the value of "rhost" of the object
5
+ # is "*.laposte.net" or "*.orange.fr".
6
+ # This class is called only Sisimai::Data class.
7
+ module FrancePTT
8
+ class << self
9
+ # Imported from p5-Sisimail/lib/Sisimai/Rhost/FrancePTT.pm
10
+ CodeTable = {
11
+ :'103' => 'blocked', # Service refuse. Veuillez essayer plus tard.
12
+ :'104' => 'toomanyconn', # Too many connections, slow down. LPN105_104
13
+ :'105' => nil, # Veuillez essayer plus tard.
14
+ :'109' => nil, # Veuillez essayer plus tard. LPN003_109
15
+ :'201' => nil, # Veuillez essayer plus tard. OFR004_201
16
+ :'305' => 'securityerror', # 550 5.7.0 Code d'authentification invalide OFR_305
17
+ :'401' => 'blocked', # 550 5.5.0 SPF: *** is not allowed to send mail. LPN004_401
18
+ :'402' => 'securityerror', # 550 5.5.0 Authentification requise. Authentication Required. LPN105_402
19
+ :'403' => 'rejected', # 5.0.1 Emetteur invalide. Invalid Sender.
20
+ :'405' => 'rejected', # 5.0.1 Emetteur invalide. Invalid Sender. LPN105_405
21
+ :'415' => 'rejected', # Emetteur invalide. Invalid Sender. OFR_415
22
+ :'416' => 'userunknown', # 550 5.1.1 Adresse d au moins un destinataire invalide. Invalid recipient. LPN416
23
+ :'417' => 'mailboxfull', # 552 5.1.1 Boite du destinataire pleine. Recipient overquota.
24
+ :'418' => 'userunknown', # Adresse d au moins un destinataire invalide
25
+ :'420' => 'suspend', # Boite du destinataire archivee. Archived recipient.
26
+ :'421' => 'rejected', # 5.5.3 Mail from not owned by user. LPN105_421.
27
+ :'423' => nil, # Service refused, please try later. LPN105_423
28
+ :'424' => nil, # Veuillez essayer plus tard. LPN105_424
29
+ :'506' => 'spamdetected', # Mail rejete. Mail rejected. OFR_506 [506]
30
+ :'510' => 'blocked', # Veuillez essayer plus tard. service refused, please try later. LPN004_510
31
+ :'513' => nil, # Mail rejete. Mail rejected. OUK_513
32
+ :'514' => 'mesgtoobig', # Taille limite du message atteinte
33
+ }.freeze
34
+
35
+ # Detect bounce reason from Oranage or La Poste
36
+ # @param [Sisimai::Data] argvs Parsed email object
37
+ # @return [String] The bounce reason for Orange or La Poste
38
+ def get(argvs)
39
+ return nil unless argvs
40
+ return nil unless argvs.is_a? Sisimai::Data
41
+ return argvs.reason if argvs.reason.size > 0
42
+
43
+ statusmesg = argvs.diagnosticcode
44
+ reasontext = ''
45
+
46
+ if cv = statusmesg.match(/\b(LPN|OFR|OUK)(_[0-9]{3}|[0-9]{3}[-_][0-9]{3})\b/)
47
+ # OUK_513, LPN105-104, OFR102-104
48
+ v = sprintf("%03d", (cv[1] + cv[2])[-3, 3])
49
+ reasontext = CodeTable[v.to_sym] || 'undefined'
50
+ end
51
+ return reasontext
52
+ end
53
+
54
+ end
55
+ end
56
+ end
57
+ end
58
+