flight 001: iphone mail 文字コード判別
.
よく「iphone mail で魔法の文字を入れて送信すれば文字化けを回避できる」
という記事を見かけるとおり、
送信側の文字コードが、通例では
旧来のメーラーは、jis ( iso-2022-jp )
昨今のメーラーは、utf8
と、ほぼ固定(一部例外有)だったけど
iphone mail は
文字コード可変送信型メーラー
に、なっている
sendmail するにしても、web に渡すにしても
メールパースする場合、なんとも厄介この上ない
ひとまずやってみたので一例
[ 食感 (要点) ]
- 件名 mime encode 値 と 本文 Jcode::getcode 値 を用いて判定
- 上記 2つ ( 件名 と 本文 ) の判定違いも注意
- getcode の特性上、判定できないものもある
- 他国語も もれなく 注意必要
[ お品書き ]
1. キッチン ( 使用環境、検証環境 )
2. 食材
3. 仕込
4. 調理 1 - 通常ケース
5. 調理 2 - 特殊 1 - ハートマーク
6. 調理 3 - 特殊 2 - 波ダッシュ、他
7. 調理 4 - イレギュラー 1 - 中国語
8. 調理 5 - イレギュラー 2 - 判定不能
9. デザート ( まとめ、あと書き )
[ 1. キッチン ( 使用環境、検証環境 ) ]
xserver x10
perl 5.16.3
iphone SE (iOS 9.3.5)
iPhone Mail (13G36)
[ 2. 食材 ]
mime encode された (件名 $subject)
例: =?UTF-8?Q?Jcode::getcode (本文 $body) の値
例: utf8
[ 3. 仕込 ]
パース後、こんな感じで、件名 ( subject ) と 本文 ( body ) を入れておく
use Jcode;
use Encode;
use MIME::Parser;
# =============================
# 件名
my $subject = $header->get('Subject');
chomp($subject);
$sub01 = $subject;
$sub02 = substr($sub01, 2, 3); # 3文字抜き
$sub03 = substr($sub01, 6, 2); # EUC用にハイフン後2文字抜き
$sub04 = substr($sub01, 2, 6); # 5文字抜き
# 半角 (1バイト) のみチェック ( = 1 なら半角のみ )
# ( 本来 件名に 2バイトが入ることはないが念の為 )
$sub05 = 0;
if ( $sub01 =~ /^[\x20-\x7E]+$/ ) {
$sub05 = 1;
}
# 件名なしチェック
$sub06 = 0;
if ( $sub01 eq '' ) {
$sub06 = 1;
}
# =============================
# 本文 ( multipart 無しだったとして )
$body = $entity->bodyhandle->as_string;
chomp($body);
$bo01 = Jcode::getcode($body);
# =============================
[ 4. 調理 1 - 通常ケース ]
(1) 件名、本文 ともに 日本語
sub01: =?iso-2022-jp?B?GyRCJCIbKEI=?=
sub02: iso
sub03: 20
sub04: iso-20
sub05: 1
sub06: 0
body(bo01): jis
-> 件名 iso-2022-jp, 本文 jis のシンプル
(2) 件名(例: aaa)、本文 ともに 英語(英数半角/1バイト)
sub01: aaa
sub02: a
sub03:
sub04: a
sub05: 1
sub06: 0
body(bo01): ascii
-> 件名 mime encode 無し(ascii), 本文 ascii これもシンプル
[ 5. 調理 2 - 特殊 1 ]
(1) 件名、本文 ともに ハート( ♡ )
sub01: =?euc-kr?Q?=A2=BD_su?=
sub02: euc
sub03: kr
sub04: euc-kr
sub05: 1
sub06: 0
body(bo01): euc
-> 件名 euc-kr, 本文 euc
euc-kr ( 韓国系 euc ) 初めて見ました
これいわゆる utf8 固定になると言われている文字列で、
署名に入れると utf8 になる ? ( getcode では utf8 にならないのか未検証 )
[ 6. 調理 3 - 特殊 2 ]
(1) 件名、本文 ともに 0x8160 ( sjis ):
通称 波ダッシュ
sub01: =?cp932?Q?150=81`30?=
sub02: cp9
sub03: 2?
sub04: cp932?
sub05: 1
sub06: 0
body(bo01): sjis
-> 件名 cp932, 本文 sjis
メーラーで cp932 も初めて見ました
波ダッシュは、web ページから貼り付けて送信すると入ってきます
(2) 件名、本文 ともに 0x8166 ( sjis ):
2バイトアポストロフィー ? ( 正式名分かってません )
sub01: =?cp932?Q?You=81fve?=
sub02: cp9
sub03: 2?
sub04: cp932?
sub05: 1
sub06: 0
body(bo01): sjis
-> 件名 cp932, 本文 sjis
2バイトアポストロフィー は、海外からのメールなんかでたまに入ってきて、
iso-2022-jp や utf8 で何も考えず転送送信すると文字化けてます
しょうがないので unpack して 1バイトアポストロフィーに変換します
$bod01 = $body;
$bod01 =~ s/^\s*(.*?)\s*$/$1/;
$bod02 = uc unpack("H*", $bod01);
$bod02 =~ s/8166/27/mg;
$bod03 = pack("H*", $bod02);
[ 7. 調理 4 - イレギュラー 1 ]
(1) 件名、本文 ともに 中国語
sub01: =?GB2312?Q?60_=D5=E2?=
sub02: GB2
sub03: 12
sub04: GB2312
sub05: 1
sub06: 0
body(bo01): euc
-> 件名 GB2312, 本文 euc
subject と body の判定が一致しない ...
Jcode::getcode では 以下の値が取得できるらしいです
binary / ascii / euc / sjis / jis / ucs2 / utf8 / undef
euc の場合、
euc-jp (日本系) / euc-cn (中国系) / euc-tw (台湾系) / euc-kr (韓国系)
など、いろいろあるので、このケースは、euc-cn と推測
でも、件名の GB2312 から本文も同じく以下にしたら文字化けなく OK
Encode::from_to($body, 'GB2312', 'utf8');
ただし、簡体字 / 繁体字 などの違いで、Big5 や GB18030 などに変わるのかも
[ 8. 調理 5 - イレギュラー 2 ]
件名 が 空 で、本文 の getcode が undef など判定不能 の場合は、もうどうしようもない
実際、getcode で、binary / ucs2 / undef あたりになると、どうしたものか
でも、テストケースも思いつかないので unknown 判定で、保留
[ 9. デザート ( あと書き ) ]
もちろん件名と本文が、同一文字コードではないケースも普通の話なので、
同一の判定をすることはできないけど
getcode 判定は 時として 曖昧なので、mime encode も用いて総合判断する
※以下とても注意!
(1) perl の version
(2) Jcode の version
(3) iphone の 機種
(4) iOS の version
(5) iphone mail の version
によって判定値 は 変わる可能性があるので注意が必要
(あくまでも参考程度に。最新iOSでは変わっているかも)
今後も apple 様の思うままに仕様変更はありそう
.
Author And Source
この問題について(flight 001: iphone mail 文字コード判別), 我々は、より多くの情報をここで見つけました https://qiita.com/cxfgp/items/40455cdecfb0f2f6ca95著者帰属:元の著者の情報は、元のURLに含まれています。著作権は原作者に属する。
Content is automatically searched and collected through network algorithms . If there is a violation . Please contact us . We will adjust (correct author information ,or delete content ) as soon as possible .