Perl で携帯電話に絵文字入りメールを送る方法

各キャリアの文字コード体系とメール送信方法の関係

各キャリアの文字コード体系の概説と、このページで紹介するメール送信方法との関係を概説します。
文字コード体系の技術的詳細事項は公開されていない部分もありますので、予想が含まれています。

JISコード概説

各キャリアの文字コードとの関連を説明する前にJISコード(ISO-2022-JP)について概要を説明します。

上に、

print pack("c*", hex('a4'), hex('a2'));

print pack("c*", hex('82'), hex('a0'));

で「あ」が表示される、と書きましたが、逆に、文字からコードに変換するには unpack を使用します。

print unpack('H*', 'あ');

を実行すると、Windows環境では(=プログラムが Shift_JIS で記載されていれば)「82a0」が、一般的なUNIX系OS環境では(=プログラムが EUC-JP で記載されていれば)「a4a2」が表示されます。

Windows のIMEパッドで「あ」の文字コードを調べると、「82a0」になっているので、これはプログラムの結果と一致します。

では、上記の1行のコードをJIS(ISO-2022-JP)で保存して実行すると、何が表示されるでしょうか?
Windows の IMEパッドだと、「あ」のJISコードは「2422」になっています。

「あ」のJISコードは「2422」なので、他の文字コードと同様、「2422」と表示されることを期待するところですが、実際に表示されるのは「1b244224221b2842」という長い文字列です。

これは、ISO-2022-JP の決まりの「ASCII 文字以外を使う時は、先に合図をする」という約束に従って「あ」を表現したからです。
「1b244224221b2842」は「1b2442」「2422」「1b2842」という3つの部分に分けることができます。真中のパートに JISで「あ」を表す「2422」がちゃんと表示されています。
大雑把に言うと、「1b2442」は「これから日本語を使いますよ」という合図、「1b2842」は「これより先はASCIIに戻りますよ」という合図です。ISO-2022-JP では、ASCII と日本語(大雑把に言うと全角文字)が切り替わるたびにこれらの合図を間に挟みます。(細かく言うと「行頭は必ずASCIIとみなす」等のルールもあります。)

ちなみに「1b」は特殊文字「エスケープ」を表す文字コードで「1b2442」や「1b2842」は「エスケープシーケンス」と呼ばれる文字列です。(文字列といっても、表示文字はありません。)

「これはAです。」という文を各文字コード体系のコードで表すと、以下のようになります。

Shift_JISとEUC-JPの場合

  A
Shift_JIS 82b1 82ea 82cd 41 82c5 82b7 8142
EUC-JP a4b3 a4ec a4cf 41 a4c7 a4b9 a1a3

ISO-2022-JP(JIS)の場合

    A    
1b2442
(日本語開始)
2433 246c 244f 1b2842
(ASCIIに戻る)
41 1b2442
(日本語開始)
2447 2439 2123 1b2842
(ASCIIに戻る)

JIS と他のコード体系との違いのポイントは、以下の通りです。

(1)
JISは、ASCIIと日本語をエスケープシーケンスの出現によって区別する。
例えば、「24」というコードが出現した時、それがASCIIの24(「$」に該当)なのか「こ(2433)」の前半なのかは、その部分を見ただけでは判断できない。
EUC-JPやShift_JIS はそのような方法を採らず、出てきたコードのみで文字との対応を判断する。

(2)
ASCII文字(上記例だと「A」)の文字コードは、上記のどのコード体系でも、同じコード(上記例だと「41」)が同じ文字(上記例だと「A」)を表す。

本文作成時の文字列操作

次に、上に挙げたサンプルコードを例に、実際の本文作成の手順にどういう操作を行っているかを概説します。

以下の、$body 部分にだけ注目します。

my $body = '今日のお天気は%_emoji_sunny_%です。';

$body = Jcode->new($body, 'euc')->jis;
#$body = Jcode->new($body, 'sjis')->jis; #Shift_JISでプログラムしている場合

$body =~ s/%_emoji_sunny_%/&packcode('f9','8b')/eg;

まず、原稿作成部分です。

my $body = '今日のお天気は%_emoji_sunny_%です。';

「JISコード概説」で紹介した unpack 関数で、$body のコード列を調べると、下表のようになっています。
具体的には、以下のようなコードでコード列を調べました。

my $body = '今日のお天気は%_emoji_sunny_%です。';
print "EUC body unpack = ",unpack('H*', $body),"\n";

  →下表へ
Shift_JIS 8da1 93fa 82cc 82a8 9356 8b43 82cd
EUC-JP baa3 c6fc a4ce a4aa c5b7 b5a4 a4cf

続き→   % _ e m o j i _ s u n n y _ %
Shift_JIS 25 5f 65 6d 6f 6a 69 5f 73 75 6e 6e 79 5f 25 82c5 82b7 8142
EUC-JP 25 5f 65 6d 6f 6a 69 5f 73 75 6e 6e 79 5f 25 a4c7 a4b9 a1a3

では次に、これをJISに変換した場合はどうなるでしょうか? 以下のプログラムで調べます。

#EUC-JPでプログラミングしている場合

#JISに変換
$body = Jcode->new($body, 'euc')->jis;

#JISのコード列
print "JIS body unpack = ",unpack('H*', $body),"\n";

    % _ e m o j i →下表へ
1b2442
(日本語開始)
3a23 467c 244e 242a 4537 3524 244f 1b2842
(ASCIIに戻る)
25 5f 65 6d 6f 6a 69

続き→ _ s u n n y _ %    
5f 73 75 6e 6e 79 5f 25 1b2442
(日本語開始)
2447 2439 2123 1b2842
(ASCIIに戻る)

文字列開始時、「%_emoji_sunny_%」の前後、文字列の最後に、エスケープシーケンスが含まれているのが分ります。

では、今度は、「%_emoji_sunny_%」の部分を絵文字コードに置き換えます。

$body =~ s/%_emoji_sunny_%/&packcode('f9','8b')/eg; #Voddafone の太陽の絵文字

このコードを実行すると、「%_emoji_sunny_%」に該当するコード列「255f656d6f6a695f73756e6e795f25」部分だけが、pack された「f98b」に置き換わります。

    →下表へ
置換前 1b2442 3a23 467c 244e 242a 4537 3524 244f
 
置換後 1b2442
(日本語開始)
3a23 467c 244e 242a 4537 3524 244f

続き→     % _ e m o j i _ s u n n y _ % →下表へ
置換前 1b2842 25 5f 65 6d 6f 6a 69 5f 73 75 6e 6e 79 5f 25
 
置換後 1b2842
(ASCIIに戻る)
f98b

続き→      
置換前 1b2442 2447 2439 2123 1b2842
 
置換後 1b2442
(日本語開始)
2447 2439 2123 1b2842
(ASCIIに戻る)

置換後の本文文字列は、本来なら ASCII の領域である「1b2842」と「1b2442」の間に、絵文字コード(この場合は「f98b」)が含まれた形になります。

このように、JISの文字コードルール上はありえない形ですが、このページで紹介する方法では、送信するメール本文はこのような構成になっています。

なお、JISで使用するASCIIコードは「00」から「7f」の範囲に収まりますので、絵文字コードに含まれている「f9」「8b」はどちらも本来ならば絶対に出現することのない値です。

メール送信経路概要

送信されたメールは、以下のような経路を通って受信者に届けられます。

通常のメールの場合、受信者のメールアドレスを管理するメールサーバ(図中の「POPサーバ」)に受信者がアクセスし、メールを受信します。この時、通常はメールサーバはメールの本文等に加工は加えず、送信されたままのメール本文を受信者が受信し、受信者が利用するパソコン等にインストールされているメールソフトで受信したメールを解釈し表示します。

携帯端末への送信の場合、受信者のメールアドレスを管理するメールサーバは携帯キャリアのサーバです。キャリアによって異なり、また詳細な仕様は公開されていないようですが、サーバ側でメール内容の加工(例えば本文が長い場合、短く切ってしまったり分割する)をしてから個々の携帯端末宛てに送信されるようです。

通常のメールの場合(一般的な場合)

送信者
(プログラム等含)

送信
SMTPサーバ
(送信者が
利用可能)

メール中継
中継
SMTPサーバ
(0~n個)

メール中継
POPサーバ
(受信者が
利用可能)

受信
受信者の
メールソフト等
            ↑通常何も加工しない    
       

携帯メールアドレス宛てのメールの場合

     
  ↓必要に応じて加工する    
送信者
(プログラム等含)

送信
SMTPサーバ
(送信者が
利用可能)

メール中継
中継
SMTPサーバ
(0~n個)

メール中継
携帯キャリアの
メールサーバ

送信
受信者の
携帯端末

文字コード体系 – EZ Web と Docomo の場合

(この項の内容にはかなり予想が含まれています。)

上記の通り、携帯端末宛てのメールの場合、メールは携帯キャリアのサーバで一定の加工をされてから、携帯端末に送信されているようです。

送信されたメールの文字コードがサーバで変換されてから個々の携帯端末に送信されているのか、個々の携帯端末上のメール表示アプリケーションによって送信されたメールの文字コードを解釈して表示しているのかは分りませんが、EZ Web と Docomo の場合、JIS(日本語メールの標準的な文字コード)で送信されたメールは一旦 Shift_JIS に変換され、携帯端末上で表示されているようです。

この変換の際、JISコードの上のASCII部分には手をつけずに変換を行っているのではないか、というのが、EZ Web と Docomo の場合の仕様の予想です。

Docomoの絵文字コードを例にすると、以下のような感じです。

    →下表へ
置換前 1b2442
(日本語開始)
3a23 467c 244e 242a 4537 3524 244f
 
置換後 (日本語が始まるから
Shift_JISに変換しよう)
8da1 93fa 82cc 82a8 9356 8b43 82cd

続き→     (晴)    
置換前 1b2842
(ASCIIに戻る)
f89f 1b2442
(日本語開始)
2447 2439 2123 1b2842
(ASCIIに戻る)
 
置換後 (ASCIIに戻ったから
何もしなくていいな)
f89f (日本語が始まるから
Shift_JISに変換しよう)
82c5 82b7 8142 (ASCIIに戻ったから
何もしなくていいな)

「1b2842」以降の(本来なら)ASCIIコードの部分のコードは変換対象からはずれるので、ここに Shift_JIS コードで絵文字を挿入しておくと、全体を Shift_JIS へ変換した後の文字列は、以下のような、全体を初めから Shift_JIS で表記した場合と同じになります。

(晴)
8da1 93fa 82cc 82a8 9356 8b43 82cd f89f 82c5 82b7 8142

文字コード体系 – Vodafone の場合

Vodafone の文字コード体系は、どうやらもう少し込み入っています。

公式な技術文書には、絵文字は以下のように記述する、と記載があります。

[ESC] $ [GEFOPQ のいずれか] [1バイトの文字コード(0x21-0x7aの範囲)]* [SI]

Vodafone のウェブサイトに記載されているWebコードは、この記述に該当します。
Webコード表だと、1文字ずつコーディングする表記になっていますが、絵文字が続く場合、[1バイトの文字コード(0x21-0x7aの範囲)]を繰り返すことによって連続した絵文字を表記できます。

例えば、以下のコードは、「男の子の顔」「女の子の顔」「男性の顔」「女性の顔」を続けて表示します。

[ESC]$G!"$%[SI]

ISO-2022-JP のコーディング方式に発想が似ています。Shift_JIS文書中でもUTF-8文書中でもこの記述が使える、というのが、Vodafoneの絵文字の公式な仕様です。

このページで紹介した方法の場合、このWebコード体系は使用しておらず、メール(JIS)の場合、Web(Shift_JIS)の場合、それぞれ別のコード体系(一部重複)で絵文字を表示します。

というより、別のコーディングでも絵文字が表示できました、というのがより正しい説明です。
公式な仕様ではないので、端末によっては対応していない可能性があります。
また、3G 端末は基本の文字コードが従来の Shift_JIS ではなく UTF-8 なので対応はありません。

Vodafone が提供する技術文書には 3G 端末は内部的に別の外字体系をもっており、3G端末への送信の場合、従来のコード体系(公式のWebコード体系)のデータはサーバで変換を掛けて端末に送信している、と記載があります。ただし、Webページに記載されたコードの場合の話です。

では、従来端末に、公式のWebコード方式で絵文字を記載したメールを送るとどうなるでしょうか?
試した端末が限られているので、確実な結果ではありませんが、ちょっと込み入った挙動になります。

《結果》
・ロングメールのサブジェクトに関してはOK
・ロングメールの本文は同じ表記でもNG
・同じ内容を短く切ってショートメール該当の長さにすると、サブジェクトに関してもNG
・ロングメールのサブジェクトでも、着信連絡後、全文未受信の場合はNG。
 全文を受信すると、サブジェクト中の絵文字のみ意図どおり表示される

端末でなのかサーバでなのか分りませんが、ある種のコード変換がされているようです。

上記に紹介してきた送信用コードでメールを送ると、このコード変換をすり抜けることができる、というのが従来端末での絵文字送信が成功する理由ではないかと思います。

コード変換をすり抜けたメール本文、サブジェクトは「そのまま」のコードで端末上で表示されますが、3G端末の場合は別のコード体系を持っているのでうまくいかない…
メールアドレスからは使用している端末を類推することはできないので、3Gとそれ以外の端末が混在している現在、Vodafone ユーザに同じコードで絵文字メールを送信する事はできないようです。

Softbank 3Gへの対応(2007-12-10 追記)

いつの間にか(?)Vodafone はSoftbank になりました。
絵文字の仕様は変わっていないようですが、上記までの方法では 3G 端末に絵文字を送信できませんので、その解決方法の概要を書いておきます。
「同じコードで3キャリアに送信できる」という当初の目論見は儚くも崩れ去りました。

・3G 端末対応としては、HTMLメールにするのが基本的な対応。

・mutipart/alternative 形式で HTML形式とテキストメールを両方送信する。

・HTML部分は 3G 端末用として、ウェブコードで絵文字を含んだHTMLメールにする。
 この時HTMLの文字コードは UTF-8 にする。

・HTMLメールの文字コードはメール(mutipart)のヘッダ情報ではなく、本文のHTMLコード内にメタタグで含める。
 【重要:そうしないと文字化けする端末があります】

・テキスト部分は従来端末用とする。
 文字コードは JIS(ISO-2022-JP)にして、絵文字は上述のコードを含める。

・メールサブジェクトに絵文字を含めることは諦める。

更新履歴

2004-11-15 初出
2004-12-24 「各キャリアの場合の対処」の EZ Web と i-mode についての記載修正(動作検証後)
2005-02-04 KDDI の絵文字データのCSV公開
2005-04-15 参考書籍情報追加、文字コード検索ツール(新規公開)へのリンク追加
       その他詳細情報追加
2005-04-16 冗長な記載を削除
2005-05-12 メール送信用サンプルコード追加
2005-05-25 各キャリアの文字コード体系とメール送信方法の関係-JISコード概説 追加
2005-05-26 各キャリアの文字コード体系とメール送信方法の関係-本文作成時の文字列操作 追加
2005-06-08 「メール送信経路概要」、「文字コード体系 – EZ Web と Docomo の場合」 追加
2005-08-11 「文字コード体系 – Vodafone の場合」 追加
2006-03-31 同上パート追記
2007-12-10 Softbank 3Gへの対応 追記