Skip to content

Commit

Permalink
Implement Sisimai::Rhost::IUA and tests
Browse files Browse the repository at this point in the history
  • Loading branch information
azumakuniyuki committed Dec 3, 2019
1 parent 0a12379 commit 256187e
Show file tree
Hide file tree
Showing 6 changed files with 165 additions and 1 deletion.
1 change: 1 addition & 0 deletions lib/sisimai/rhost.rb
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ class << self
'mailstore1.secureserver.net' => 'GoDaddy',
'aspmx.l.google.com' => 'GoogleApps',
'gmail-smtp-in.l.google.com' => 'GoogleApps',
'.email.ua' => 'IUA',
'lsean.ezweb.ne.jp' => 'KDDI',
'msmx.au.com' => 'KDDI',
'.qq.com' => 'TencentQQ',
Expand Down
39 changes: 39 additions & 0 deletions lib/sisimai/rhost/iua.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
module Sisimai
module Rhost
# Sisimai::Rhost detects the bounce reason from the content of Sisimai::Data
# object as an argument of get() method when the value of "rhost" of the object
# is "*.email.ua". This class is called only Sisimai::Data class.
module IUA
class << self
# Imported from p5-Sisimail/lib/Sisimai/Rhost/IUA.pm
ErrorCodes = {
# http://mail.i.ua/err/$(CODE)
'1' => 'norelaying', # The use of SMTP as mail gate is forbidden.
'2' => 'userunknown', # User is not found.
'3' => 'suspend', # Mailbox was not used for more than 3 months
'4' => 'mailboxfull', # Mailbox is full.
'5' => 'toomanyconn', # Letter sending limit is exceeded.
'6' => 'norelaying', # Use SMTP of your provider to send mail.
'7' => 'blocked', # Wrong value if command HELO/EHLO parameter.
'8' => 'rejected', # Couldn't check sender address.
'9' => 'blocked', # IP-address of the sender is blacklisted.
'10' => 'filtered', # Not in the list Mail address management.
}.freeze

# Detect bounce reason from https://www.i.ua/
# @param [Sisimai::Data] argvs Parsed email object
# @return [String] The bounce reason at https://www.i.ua/
def get(argvs)
return argvs.reason unless argvs.reason.empty?

if cv = argvs.diagnosticcode.downcase.match(%r|[.]i[.]ua/err/(\d+)|)
return ErrorCodes[cv[1]] if ErrorCodes.key?(cv[1])
end
return ''
end

end
end
end
end

70 changes: 70 additions & 0 deletions set-of-emails/maildir/bsd/rhost-iua-01.eml
Original file line number Diff line number Diff line change
@@ -0,0 +1,70 @@
Return-Path: <>
X-Original-To: nekochan@example.co.jp
Delivered-To: nekochan@example.co.jp
Received: by mail.example.co.jp (Postfix)
id 18513041C2DA; Thu, 29 Apr 2019 23:34:45 +0900 (JST)
Date: Thu, 29 Apr 2019 23:34:45 +0900 (JST)
From: MAILER-DAEMON@example.co.jp (Mail Delivery System)
Subject: Undelivered Mail Returned to Sender
To: nekochan@example.co.jp
Auto-Submitted: auto-replied
MIME-Version: 1.0
Content-Type: multipart/report; report-type=delivery-status;
boundary="0E1D4CDC0054.1562628010/mail.example.co.jp"
Message-Id: <20190429233445.18513041C2DA@mail.example.co.jp>

This is a MIME-encapsulated message.

--0E1D4CDC0054.1562628010/mail.example.co.jp
Content-Description: Notification
Content-Type: text/plain; charset=us-ascii
This is the mail system at host mail.example.co.jp.
I'm sorry to have to inform you that your message could not
be delivered to one or more recipients. It's attached below.
For further assistance, please send mail to postmaster.
If you do so, please include this problem report. You can
delete your own text from the attached returned message.
The mail system
<neko@email.example.ua>: host mx3.email.ua[185.187.81.214] said: 550 Mailbox is
frozen. See http://mail.i.ua/err/3/ (in reply to RCPT TO command)
--0E1D4CDC0054.1562628010/mail.example.co.jp
Content-Description: Delivery report
Content-Type: message/delivery-status
Reporting-MTA: dns; mail.example.co.jp
X-Postfix-Queue-ID: 0E1D4CDC0054
X-Postfix-Sender: rfc822; nekochan@example.co.jp
Arrival-Date: Thu, 29 Apr 2019 23:34:45 +0900 (JST)
Final-Recipient: rfc822; neko@email.example.ua
Action: failed
Status: 5.0.0
Remote-MTA: dns; mx3.email.ua
Diagnostic-Code: smtp; 550 Mailbox is frozen. See http://mail.i.ua/err/3/
--0E1D4CDC0054.1562628010/mail.example.co.jp
Content-Description: Undelivered Message
Content-Type: message/rfc822
Return-Path: <nekochan@example.co.jp>
Received: by mail.example.co.jp (Postfix, from userid 2022)
id 0E1D4CDC0054; Thu, 29 Apr 2019 23:34:45 +0900 (JST)
To: neko@email.example.ua
Subject: Nyaan
From: <kijitora@example.com>
MIME-Version: 1.0
Content-Type: text/plain; charset=ISO-2022-JP
Content-Transfer-Encoding: 7bit
Message-Id: <20190429233445.0E1D4CDC0054@mail.example.co.jp>
Date: Thu, 29 Apr 2019 23:34:45 +0900 (JST)
Nyaan
--0E1D4CDC0054.1562628010/mail.example.co.jp--
2 changes: 1 addition & 1 deletion spec/sisimai/mail/maildir_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@

describe Sisimai::Mail::Maildir do
samplemaildir = './set-of-emails/maildir/bsd'
allofthefiles = 447
allofthefiles = 448
let(:mailobj) { Sisimai::Mail::Maildir.new(samples) }
let(:mockobj) { Sisimai::Mail::Maildir.new(invalid) }

Expand Down
53 changes: 53 additions & 0 deletions spec/sisimai/rhost/iua_spec.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
require 'spec_helper'
require 'sisimai/mail'
require 'sisimai/data'
require 'sisimai/message'
require 'sisimai/rhost/iua'

describe Sisimai::Rhost::IUA do
rs = {
'01' => { 'status' => %r/\A5[.]0[.]0\z/, 'reason' => %r/suspend/ },
}
describe 'bounce mail from IUA' do
rs.each_key.each do |n|
emailfn = sprintf('./set-of-emails/maildir/bsd/rhost-iua-%02d.eml', n)
next unless File.exist?(emailfn)

mailbox = Sisimai::Mail.new(emailfn)
mtahost = %r/\Amx[0-9]+[.]email[.]ua\z/
next unless mailbox

while r = mailbox.read do
mesg = Sisimai::Message.new(data: r)
it('is Sisimai::Message object') { expect(mesg).to be_a Sisimai::Message }
it('has array in "ds" accessor' ) { expect(mesg.ds).to be_a Array }
it('has hash in "header" accessor' ) { expect(mesg.header).to be_a Hash }
it('has hash in "rfc822" accessor' ) { expect(mesg.rfc822).to be_a Hash }
it('has From line in "from" accessor' ) { expect(mesg.from.size).to be > 0 }

mesg.ds.each do |e|
example('spec is "SMTP"') { expect(e['spec']).to be == 'SMTP' }
example 'recipient is email address' do
expect(e['recipient']).to match(/\A.+[@].+[.].+\z/)
end
example('status is DSN') { expect(e['status']).to match(/\A\d[.]\d[.]\d\z/) }
example('command is SMTP command') { expect(e['command']).to match(/\A[A-Z]{4}\z/) }
example('date is not empty') { expect(e['date']).not_to be_empty }
example('diagnosis is not empty') { expect(e['diagnosis']).not_to be_empty }
example('action is not empty') { expect(e['action']).not_to be_empty }
example('rhost is mx*.qq.com') { expect(e['rhost']).to match(mtahost) }
example('alias exists') { expect(e['alias']).not_to be_nil }
example('agent is Email::*') { expect(e['agent']).to match(/\AEmail::/) }
end

data = Sisimai::Data.make(data: mesg)
data.each do |e|
example('reason is String') { expect(e.reason.size).to be > 0 }
example('reason matches') { expect(e.reason).to match(rs[n]['reason']) }
end
end
end

end
end

1 change: 1 addition & 0 deletions spec/sisimai/rhost_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,7 @@
'smtpz4.laposte.net',
'smtp-in.orange.fr',
'mx2.qq.com',
'mx3.email.ua',
]
v.each do |e|
context "(#{e})" do
Expand Down

0 comments on commit 256187e

Please sign in to comment.