Skip to content

Commit

Permalink
Merge pull request #311 from sisimai/go-sisimai-compatibility-7e89
Browse files Browse the repository at this point in the history
go-sisimai compatibility 7e89
  • Loading branch information
azumakuniyuki authored Oct 9, 2024
2 parents cbf9ebf + 90485fc commit 03ab0da
Show file tree
Hide file tree
Showing 25 changed files with 304 additions and 323 deletions.
14 changes: 7 additions & 7 deletions lib/sisimai/fact.rb
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ class Fact
require 'sisimai/address'
require 'sisimai/datetime'
require 'sisimai/time'
require 'sisimai/smtp/error'
require 'sisimai/smtp/failure'
require 'sisimai/smtp/command'
require 'sisimai/string'
require 'sisimai/rhost'
Expand Down Expand Up @@ -388,7 +388,7 @@ def self.rise(**argvs)
if thing['reason'].empty? || RetryIndex[thing['reason']]
# The value of "reason" is empty or is needed to check with other values again
re = thing['reason'].empty? ? 'undefined' : thing['reason']
thing['reason'] = Sisimai::Rhost.get(thing) || Sisimai::Reason.get(thing)
thing['reason'] = Sisimai::Rhost.find(thing) || Sisimai::Reason.get(thing)
thing['reason'] = re if thing['reason'].empty?
end

Expand All @@ -400,17 +400,17 @@ def self.rise(**argvs)
# The reason is not "delivered", or "feedback", or "vacation"
smtperrors = piece['deliverystatus'] + ' ' << piece['diagnosticcode']
smtperrors = '' if smtperrors.size < 4
softorhard = Sisimai::SMTP::Error.soft_or_hard(thing['reason'], smtperrors)
thing['hardbounce'] = true if softorhard == 'hard'
thing['hardbounce'] = Sisimai::SMTP::Failure.is_hardbounce(thing['reason'], smtperrors)
end

# DELIVERYSTATUS: Set a pseudo status code if the value of "deliverystatus" is empty
if thing['deliverystatus'].empty?
smtperrors = piece['replycode'] + ' ' << piece['diagnosticcode']
smtperrors = '' if smtperrors.size < 4
permanent1 = Sisimai::SMTP::Error.is_permanent(smtperrors)
permanent1 = true if permanent1 == nil
thing['deliverystatus'] = Sisimai::SMTP::Status.code(thing['reason'], permanent1 ? false : true) || ''
permanent0 = Sisimai::SMTP::Failure.is_permanent(smtperrors)
temporary0 = Sisimai::SMTP::Failure.is_temporary(smtperrors)
temporary1 = temporary0; temporary1 = false if !permanent0 && !temporary1
thing['deliverystatus'] = Sisimai::SMTP::Status.code(thing['reason'], temporary1) || ''
end

# REPLYCODE: Check both of the first digit of "deliverystatus" and "replycode"
Expand Down
50 changes: 12 additions & 38 deletions lib/sisimai/lhost/exim.rb
Original file line number Diff line number Diff line change
Expand Up @@ -381,7 +381,7 @@ def inquire(mhead, mbody)

if e['diagnosis'].start_with?('-') || e['diagnosis'].end_with?('__')
# Override the value of diagnostic code message
e['diagnosis'] = e['alterrors'] unless e['alterrors'].empty?
e['diagnosis'] = e['alterrors']

elsif e['diagnosis'].size < e['alterrors'].size
# Override the value of diagnostic code message with the value of alterrors because
Expand Down Expand Up @@ -448,47 +448,21 @@ def inquire(mhead, mbody)
#
# The value of "Status:" indicates permanent error but the value of SMTP reply code in
# Diagnostic-Code: field is "TEMPERROR"!!!!
cs = e['status'] || Sisimai::SMTP::Status.find(e['diagnosis'])
cr = e['replycode'] || Sisimai::SMTP::Reply.find(e['diagnosis'])
s1 = 0 # First character of Status as integer
r1 = 0 # First character of SMTP reply code as integer

while true
# "Status:" field did not exist in the bounce message
break if cs
break unless cr

# Check SMTP reply code, Generate pseudo DSN code from SMTP reply code
r1 = cr[0, 1].to_i
if r1 == 4
# Get the internal DSN(temporary error)
cs = Sisimai::SMTP::Status.code(e['reason'], true)

elsif r1 == 5
# Get the internal DSN(permanent error)
cs = Sisimai::SMTP::Status.code(e['reason'], false)
end
break
end
re = e['reason'] || ''
cr = Sisimai::SMTP::Reply.find(e['diagnosis'], e['status'] || '') || ''
cs = Sisimai::SMTP::Status.find(e['diagnosis'], cr)
cv = ''

s1 = cs[0, 1].to_i if cs
v1 = s1 + r1
v1 << e['status'][0, 1].to_i if e['status']
if cr[0,1] == "4" || re == "expired" || re == "mailboxfull"
# Set the pseudo status code as a temporary error
cv = Sisimai::SMTP::Status.code(re, true)

if v1 > 0
# Status or SMTP reply code exists, Set pseudo DSN into the value of "status" accessor
e['status'] = cs if r1 > 0
else
# Neither Status nor SMTP reply code exist
cs = if %w[expired mailboxfull].include?(e['reason'])
# Set pseudo DSN (temporary error)
Sisimai::SMTP::Status.code(e['reason'], true)
else
# Set pseudo DSN (permanent error)
Sisimai::SMTP::Status.code(e['reason'], false)
end
# Set the pseudo status code as a permanent error
cv = Sisimai::SMTP::Status.code(re, false)
end
e['status'] ||= cs.to_s
e['replycode'] ||= cr
e['status'] ||= Sisimai::SMTP::Status.prefer(cs, cv, cr)
end

return { 'ds' => dscontents, 'rfc822' => emailparts[1] }
Expand Down
107 changes: 51 additions & 56 deletions lib/sisimai/reason.rb
Original file line number Diff line number Diff line change
Expand Up @@ -124,65 +124,60 @@ def anotherone(argvs)
actiontext = argvs['action'] || ''
statuscode = argvs['deliverystatus'] || ''
reasontext = Sisimai::SMTP::Status.name(statuscode) || ''
trytomatch = reasontext.empty? ? true : false
trytomatch ||= true if GetRetried[reasontext] || codeformat != 'SMTP'

catch :TRY_TO_MATCH do
while true
trytomatch = reasontext.empty? ? true : false
trytomatch ||= true if GetRetried[reasontext]
trytomatch ||= true if codeformat != 'SMTP'
throw :TRY_TO_MATCH unless trytomatch

# Could not decide the reason by the value of Status:
ClassOrder[1].each do |e|
# Trying to match with other patterns in Sisimai::Reason::* classes
p = 'Sisimai::Reason::' << e
r = nil
begin
require ModulePath[p]
r = Module.const_get(p)
rescue
warn ' ***warning: Failed to load ' << p
next
end

next unless r.match(issuedcode)
reasontext = e.downcase
break
end
throw :TRY_TO_MATCH unless reasontext.empty?

# Check the value of Status:
code2digit = statuscode[0, 3] || ''
if code2digit == '5.6' || code2digit == '4.6'
# X.6.0 Other or undefined media error
reasontext = 'contenterror'

elsif code2digit == '5.7' || code2digit == '4.7'
# X.7.0 Other or undefined security status
reasontext = 'securityerror'

elsif codeformat.start_with?('X-UNIX')
# Diagnostic-Code: X-UNIX; ...
reasontext = 'mailererror'

else
# 50X Syntax Error?
require 'sisimai/reason/syntaxerror'
reasontext = 'syntaxerror' if Sisimai::Reason::SyntaxError.true(argvs)
end
throw :TRY_TO_MATCH unless reasontext.empty?

# Check the value of Action: field, first
if actiontext.start_with?('delayed', 'expired')
# Action: delayed, expired
reasontext = 'expired'
else
# Rejected at connection or after EHLO|HELO
thecommand = argvs['smtpcommand'] || ''
reasontext = 'blocked' if %w[HELO EHLO].index(thecommand)
while trytomatch
# Could not decide the reason by the value of Status:
ClassOrder[1].each do |e|
# Trying to match with other patterns in Sisimai::Reason::* classes
p = 'Sisimai::Reason::' << e
r = nil
begin
require ModulePath[p]
r = Module.const_get(p)
rescue
warn ' ***warning: Failed to load ' << p
next
end
throw :TRY_TO_MATCH

next unless r.match(issuedcode)
reasontext = e.downcase
break
end
break unless reasontext.empty?

# Check the value of Status:
code2digit = statuscode[0, 3] || ''
if code2digit == '5.6' || code2digit == '4.6'
# X.6.0 Other or undefined media error
reasontext = 'contenterror'

elsif code2digit == '5.7' || code2digit == '4.7'
# X.7.0 Other or undefined security status
reasontext = 'securityerror'

elsif codeformat.start_with?('X-UNIX')
# Diagnostic-Code: X-UNIX; ...
reasontext = 'mailererror'

else
# 50X Syntax Error?
require 'sisimai/reason/syntaxerror'
reasontext = 'syntaxerror' if Sisimai::Reason::SyntaxError.true(argvs)
end
break unless reasontext.empty?

# Check the value of Action: field, first
if actiontext.start_with?('delayed', 'expired')
# Action: delayed, expired
reasontext = 'expired'
else
# Rejected at connection or after EHLO|HELO
thecommand = argvs['smtpcommand'] || ''
reasontext = 'blocked' if %w[HELO EHLO].index(thecommand)
end
break
end
return reasontext
end
Expand Down
1 change: 1 addition & 0 deletions lib/sisimai/reason/badreputation.rb
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ class << self
'has been temporarily rate limited due to ip reputation',
'ip/domain reputation problems',
'likely suspicious due to the very low reputation',
'none/bad reputation', # t-online.de
'temporarily deferred due to unexpected volume or user complaints', # Yahoo Inc.
"the sending mta's poor reputation",
].freeze
Expand Down
8 changes: 4 additions & 4 deletions lib/sisimai/rhost.rb
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
module Sisimai
# Sisimai::Rhost detects the bounce reason from the content of Sisimai::Fact object as an argument
# of get() method when the value of rhost of the object is listed in the results of Sisimai::Rhost
# of find() method when the value of rhost of the object is listed in the results of Sisimai::Rhost
# ->list method. This class is called only Sisimai::Fact class.
module Rhost
class << self
Expand All @@ -23,7 +23,7 @@ class << self
# Detect the bounce reason from certain remote hosts
# @param [Hash] argvs Decoded email data
# @return [String] The value of bounce reason
def get(argvs)
def find(argvs)
return nil if argvs['diagnosticcode'].empty?

remotehost = argvs['rhost'].downcase
Expand All @@ -37,7 +37,7 @@ def get(argvs)
RhostClass.each_key do |e|
# Try to match with each value of RhostClass
rhostmatch = true if RhostClass[e].any? { |a| remotehost.end_with?(a) }
rhostmatch ||= true if RhostClass[e].any? { |a| domainpart.end_with?(a) }
rhostmatch ||= true if RhostClass[e].any? { |a| a.end_with?(domainpart) }
next unless rhostmatch

modulename = 'Sisimai::Rhost::' << e
Expand All @@ -47,7 +47,7 @@ def get(argvs)
return nil if rhostclass.empty?

require rhostclass
reasontext = Module.const_get(modulename).get(argvs)
reasontext = Module.const_get(modulename).find(argvs)
return nil if reasontext.empty?
return reasontext
end
Expand Down
7 changes: 5 additions & 2 deletions lib/sisimai/rhost/apple.rb
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
module Sisimai
module Rhost
# Sisimai::Rhost detects the bounce reason from the content of Sisimai::Fact object as an argument
# of get() method when the value of "destination" of the object is "mail.icloud.com" or "apple.com".
# of find() method when the value of "destination" of the object is "mail.icloud.com" or "apple.com".
# This class is called only Sisimai::Fact class.
module Apple
class << self
Expand Down Expand Up @@ -69,7 +69,10 @@ class << self
# https://www.postmastery.com/icloud-postmastery-page/
# https://smtpfieldmanual.com/provider/apple
# @since v5.1.0
def get(argvs)
def find(argvs)
return '' unless argvs
return '' unless argvs['diagnosticcode'].size > 0

issuedcode = argvs['diagnosticcode'].downcase
reasontext = ''

Expand Down
4 changes: 2 additions & 2 deletions lib/sisimai/rhost/cox.rb
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
module Sisimai
module Rhost
# Sisimai::Rhost detects the bounce reason from the content of Sisimai::Fact object as an argument
# of get() method when the value of "destination" of the object is "charter.net". This class is
# of find() method when the value of "destination" of the object is "charter.net". This class is
# called only Sisimai::Fact class.
module Cox
class << self
Expand Down Expand Up @@ -129,7 +129,7 @@ class << self
# @return [String, Nil] The bounce reason at Cox
# @see https://www.cox.com/residential/support/email-error-codes.html
# @since v4.25.8
def get(argvs)
def find(argvs)
issuedcode = argvs['diagnosticcode']
codenumber = 0

Expand Down
4 changes: 2 additions & 2 deletions lib/sisimai/rhost/franceptt.rb
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
module Sisimai
module Rhost
# Sisimai::Rhost detects the bounce reason from the content of Sisimai::Fact object as an argument
# of get() method when the value of "rhost" of the object is "*.laposte.net" or "*.orange.fr".
# of find() method when the value of "rhost" of the object is "*.laposte.net" or "*.orange.fr".
# This class is called only Sisimai::Fact class.
module FrancePTT
class << self
Expand Down Expand Up @@ -127,7 +127,7 @@ class << self
# @return [String] The bounce reason for Orange or La Poste
# @see https://www.postmastery.com/orange-postmaster-smtp-error-codes-ofr/
# https://smtpfieldmanual.com/provider/orange
def get(argvs)
def find(argvs)
issuedcode = argvs['diagnosticcode']
reasontext = ''

Expand Down
4 changes: 2 additions & 2 deletions lib/sisimai/rhost/godaddy.rb
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
module Sisimai
module Rhost
# Sisimai::Rhost detects the bounce reason from the content of Sisimai::Fact object as an argument
# of get() method when the value of "rhost" of the object is "*.secureserver.net". This class is
# of find() method when the value of "rhost" of the object is "*.secureserver.net". This class is
# called only Sisimai::Fact class.
module GoDaddy
class << self
Expand Down Expand Up @@ -206,7 +206,7 @@ class << self
# @return [String] The bounce reason for GoDaddy
# @see https://ca.godaddy.com/help/fix-rejected-email-with-a-bounce-error-40685
# @since v4.22.2
def get(argvs)
def find(argvs)
issuedcode = argvs['diagnosticcode']
positionib = issuedcode.index(' IB') || -1
reasontext = ''
Expand Down
4 changes: 2 additions & 2 deletions lib/sisimai/rhost/google.rb
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
module Sisimai
module Rhost
# Sisimai::Rhost detects the bounce reason from the content of Sisimai::Fact object as an argument
# of get() method when the value of "rhost" of the object is "aspmx.l.google.com". This class is
# of find() method when the value of "rhost" of the object is "aspmx.l.google.com". This class is
# called only Sisimai::Fact class.
module Google
class << self
Expand Down Expand Up @@ -512,7 +512,7 @@ class << self
# @param [Sisimai::Fact] argvs Decoded email object
# @return [String] The bounce reason for Google Workspace
# @see https://support.google.com/a/answer/3726730?hl=en
def get(argvs)
def find(argvs)
return '' unless Sisimai::SMTP::Reply.test(argvs['replycode'])
return '' unless Sisimai::SMTP::Status.test(argvs['deliverystatus'])

Expand Down
4 changes: 2 additions & 2 deletions lib/sisimai/rhost/iua.rb
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
module Sisimai
module Rhost
# Sisimai::Rhost detects the bounce reason from the content of Sisimai::Fact object as an argument
# of get() method when the value of "rhost" of the object is "*.email.ua". This class is called
# of find() method when the value of "rhost" of the object is "*.email.ua". This class is called
# only Sisimai::Fact class.
module IUA
class << self
Expand All @@ -22,7 +22,7 @@ class << self
# Detect bounce reason from https://www.i.ua/
# @param [Sisimai::Fact] argvs Decoded email object
# @return [String] The bounce reason at https://www.i.ua/
def get(argvs)
def find(argvs)
return argvs['reason'] unless argvs['reason'].empty?
issuedcode = argvs['diagnosticcode'].downcase
codenumber = issuedcode.index('.i.ua/err/') > 0 ? issuedcode[issuedcode.index('/err/') + 5, 2] : 0
Expand Down
4 changes: 2 additions & 2 deletions lib/sisimai/rhost/kddi.rb
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
module Sisimai
module Rhost
# Sisimai::Rhost detects the bounce reason from the content of Sisimai::Fact object as an argument
# of get() method when the value of "rhost" of the object is "lsean.ezweb.ne.jp" or "msmx.au.com".
# of find() method when the value of "rhost" of the object is "lsean.ezweb.ne.jp" or "msmx.au.com".
# This class is called only Sisimai::Fact class.
module KDDI
class << self
Expand All @@ -14,7 +14,7 @@ class << self
# @param [Sisimai::Fact] argvs Decoded email object
# @return [String] The bounce reason for au.com or ezweb.ne.jp
# @since v4.22.6
def get(argvs)
def find(argvs)
issuedcode = argvs['diagnosticcode'].downcase
reasontext = ''

Expand Down
Loading

0 comments on commit 03ab0da

Please sign in to comment.