diff --git a/app/models/channel/email_parser.rb b/app/models/channel/email_parser.rb
index 59e3e0828..598a7cbdb 100644
--- a/app/models/channel/email_parser.rb
+++ b/app/models/channel/email_parser.rb
@@ -78,6 +78,8 @@ class Channel::EmailParser
msg = Mail::Utilities.binary_unsafe_to_crlf(msg)
mail = Mail.new(msg)
+ force_parts_encoding_if_needed(mail)
+
headers = message_header_hash(mail)
body = message_body_hash(mail)
message_attributes = [
@@ -500,6 +502,18 @@ process unprocessable_mails (tmp/unprocessable_mail/*.eml) again
private
+ # https://github.com/zammad/zammad/issues/2922
+ def force_parts_encoding_if_needed(mail)
+ mail.parts.each { |elem| force_single_part_encoding_if_needed(elem) }
+ end
+
+ # https://github.com/zammad/zammad/issues/2922
+ def force_single_part_encoding_if_needed(part)
+ return if part.charset != 'iso-2022-jp'
+
+ part.body = part.body.encoded.unpack1('M').tr('_', ' ').force_encoding('ISO-2022-JP').encode('UTF-8')
+ end
+
def message_header_hash(mail)
imported_fields = mail.header.fields.map do |f|
begin
diff --git a/spec/models/channel/email_parser_spec.rb b/spec/models/channel/email_parser_spec.rb
index d4c31ad33..fef83cc7c 100644
--- a/spec/models/channel/email_parser_spec.rb
+++ b/spec/models/channel/email_parser_spec.rb
@@ -30,6 +30,15 @@ RSpec.describe Channel::EmailParser, type: :model do
end
end
end
+
+ describe 'handling Japanese email in ISO-2022-JP encoding' do
+ let(:mail_file) { Rails.root.join('test/data/mail/mail091.box') }
+ let(:raw_mail) { File.read(mail_file) }
+ let(:parsed) { described_class.new.parse(raw_mail) }
+
+ it { expect(parsed['body']).to eq '
このアドレスへのメルマガを解除してください。
' }
+ it { expect(parsed['subject']).to eq 'メルマガ解除' }
+ end
end
describe '#process' do
diff --git a/test/data/mail/mail091.box b/test/data/mail/mail091.box
new file mode 100644
index 000000000..1110f0858
--- /dev/null
+++ b/test/data/mail/mail091.box
@@ -0,0 +1,77 @@
+Return-Path:
+Delivered-To: support@ourdomain.com
+Received: by mail.ourdomain.com (Postfix, from userid 1004)
+ id 02458FC2EB; Wed, 27 Feb 2019 09:29:45 +0900 (JST)
+DKIM-Filter: OpenDKIM Filter v2.11.0 mail.ourdomain.com 02458FC2EB
+X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on
+ HOST.ourdomain.com
+X-Spam-Level:
+X-Spam-Status: No, score=-97.0 required=5.0 tests=BAYES_50,FROM_EXCESS_BASE64,
+ HTML_MESSAGE,SPF_PASS,USER_IN_WHITELIST autolearn=no autolearn_force=no
+ version=3.4.0
+X-Spam-Report:
+ * -100 USER_IN_WHITELIST From: address is in the user's white-list
+ * 2.0 BAYES_50 BODY: Bayes spam probability is 40 to 60%
+ * [score: 0.4960]
+ * -0.0 SPF_PASS SPF: sender matches SPF record
+ * 0.0 HTML_MESSAGE BODY: HTML included in message
+ * 1.0 FROM_EXCESS_BASE64 From: base64 encoded unnecessarily
+Received: from somehost.jp (mogw0822.ocn.ad.jp [xxx.xxx.xxx.23])
+ by mail.ourdomain.com (Postfix) with ESMTP id A76D9FC2EB
+ for ; Wed, 27 Feb 2019 09:29:44 +0900 (JST)
+Received: from mf-host (mf-host.jp [xxx.xxx.xxx.79])
+ by host.jp (Postfix) with ESMTP id 614881004FA
+ for ; Wed, 27 Feb 2019 09:29:44 +0900 (JST)
+Received: from ocn-host.jp ([xxx.xxx.xxx.23])
+ by mf-smf-unw005c2 with ESMTP
+ id yn3qgKZOo017Kyn6WgDN2M; Wed, 27 Feb 2019 09:29:44 +0900
+Received: from smtp.xxx.jp ([ff.fff.fff.fff])
+ by ocn-vhost.jp with ESMTP
+ id yn6WgBk4btz0Qyn6Wg5IEF; Wed, 27 Feb 2019 09:29:44 +0900
+Received: from SL2P216MB0329.DDDDDDDDDDD.OUTLOOK.COM (unknown [xx.xxx.x.85])
+ by smtp.host.jp (Postfix) with ESMTPA
+ for ; Wed, 27 Feb 2019 09:29:44 +0900 (JST)
+From: =?iso-2022-jp?B?GyRCMixLXE9CQDUbKEI=?=
+To: "support@ourdomain.com"
+Subject: =?iso-2022-jp?B?GyRCJWElayVeJSwycj18GyhC?=
+Thread-Topic: =?iso-2022-jp?B?GyRCJWElayVeJSwycj18GyhC?=
+Thread-Index: AQHUzjN2aEAazYh0xE2h2E6iacecxA==
+X-MS-Exchange-MessageSentRepresentingType: 1
+Date: Wed, 27 Feb 2019 00:29:21 +0000
+Message-ID:
+
+Accept-Language: ja-JP, en-US
+Content-Language: ja-JP
+X-MS-Has-Attach:
+X-MS-Exchange-Organization-SCL: -1
+X-MS-TNEF-Correlator:
+X-MS-Exchange-Organization-RecordReviewCfmType: 0
+Content-Type: multipart/alternative;
+ boundary="_000_SL2P216MB032969A22C6D22226A7B3613EF740SL2P216MB0329KORP_"
+MIME-Version: 1.0
+
+--_000_SL2P216MB032969A22C6D22226A7B3613EF740SL2P216MB0329KORP_
+Content-Type: text/plain; charset="iso-2022-jp"
+Content-Transfer-Encoding: quoted-printable
+
+=1B$B$3$N%"%I%l%9$X$N%a%k%^%,$r2r=3D|$7$F$/$@$5$$!#=1B(B
+
+--_000_SL2P216MB032969A22C6D22226A7B3613EF740SL2P216MB0329KORP_
+Content-Type: text/html; charset="iso-2022-jp"
+Content-Transfer-Encoding: quoted-printable
+
+
+
+
+
+
+
+
+=1B$B$3$N%"%I%l%9$X$N%a%k%^%,$r2r=3D|$7$F$/$@$5$$!#=1B(B
+
+
+
+--_000_SL2P216MB032969A22C6D22226A7B3613EF740SL2P216MB0329KORP_--