前号: No 371 / 次号: No 373 / 一覧(note.com)へ / ブログページに戻る

メールマガジン「がんばりすぎないセキュリティ」No372 (24/09/16)

5MB送信できるメールサービスで4MBの添付ファイルが送れない理由


メールでは本文だけでなく、ファイルを添付して送ることができます。

多くのメールサービスでは1通のメールの大きさを数MB程度に制限しています。
これは、大きなデータを誤送信を防ぐには有効ですが、この制限に不満を感じる時もあります。

特に送信可能サイズの8割を越えると、おそらく送信エラーになります。

例えば5MBまで送信できるメールサービスの場合、3MBなら添付できますが、4MBは添付できません。

これは一体どういうことなのでしょうか?


1. メール(SMTP)では一部の文字しか送れない

メールの送信処理はSMTPという通信手順を使うのですが、このルール上、特定の種類の文字しか送れません。 具体的には、英文字、数字、一部の記号(!や$など)、一部の特殊記号(改行など)です。 これ以外の文字は送ってはいけないことになっているのです。(厳密にはいろいろありますが、細かい話なので省略) 「え?日本語も送れるでしょ。ウソ書いちゃいかんよ」 いえいえ、メールをSMTPで送付する時には実は日本語をわざわざアルファベットに変換して送っているのです。 「え?英語に翻訳してくれてるの?」 残念ながら、コンピュータはそんなに賢くありません。単に漢字のコード番号を英数字などに置き換えているだけです。ですので、SMTPで送受信している時の日本語はランダムにしか見えない英数字の羅列なのです。 これは日本語に限りません。フランス語のアクサン(Eの上に'記号がついたもの)やウムラウト(OやAの上に2つの点がついたもの)もSMTPでは同様に変換をして送っています。 このあたりの変換ルールの詳細はかなり以前に記事にしています。 興味のある方は読んでみてください。  No224 どうしてメール内容が化けるのか?(2021年9月配信)  https://note.com/egao_it/n/n77da2665dbe5

2. 添付ファイルはメール本文の一部

さて、添付ファイルはどうでしょうか? これも日本語と同様で、添付ファイルの内容は全て英数字に変換されています。 具体的な添付の仕方については、上記の記事の続編として記事にしていますので、ご興味のある方はどうぞ。  No225 メールの添付ファイルの仕組み(2021年9月配信)  https://note.com/egao_it/n/n5437cc3800ab

3. 添付ファイルをどうやって英数字に変換するのか?

さて、ここからが今回の本題です。 そもそも添付ファイルには当然ながら様々なデータ形式があります。 画像やOffice文書形式が代表的ですが、それ以外にも写真、動画、圧縮ファイルなどどんなファイル形式であっても添付できないと困ります。 そのためには、どんなデータであっても送付できるルールが要ります。

4. ファイルの中味はバイト列

ファイルのサイズを示す時にはバイトという単位をよく使います。 俗に言う「ギガが足りない」の「ギガ」は「ギガバイト」のことです。 1バイト=2進数8ケタですので、10進数なら0〜255が表現できるという割と小さなデータ単位です。 通常の英数字などは、この256種類の中で十分に表現できます。一方で、漢字は6万種ほどのうち、JISコードで規定されているものだけでも1万種を越えます。そのため、漢字は2バイト=2進数16ケタ(0〜65,535が表現可)あれば表現できます。(現在のUTF-8という方式では3バイトで漢字1字を表現する場合が多いです) 結局、ファイルというのは、延々とバイトデータが続いている塊とも言えます。 もちろん、その中にどんな値が詰まっているかはファイルによってバラバラです。 このバラバラなデータをどうやってメールに添付すれば良いでしょうか? さて、ここで注意していただきたいことがあります。 値としての1と文字としての"1"が違うということです。 ASCIIという文字コードでは、"1"という文字は49を使う、"A"という文字は65を使う、と決まっています。 では、1という値はどんな文字になるのか?ですが、1という値に対応する文字はありません。(厳密には制御記号という特殊文字が割当てられています) このままでは、値としての1は表記できないことになります。 ですが、上で書いたようにSMTPでは英数字しか送れませんから、何らかの工夫が必要です。その方法は後述しますが、ここでは値の1と文字の"1"は違うものだということを覚えておいてください。

5. メールで送れる形式に変換

上述の通り、メールで送る時には英数字(と一部の記号)しか送れません。とするとファイルの内容を全て2進数で表記すれば送れるはずです。 ここでは 123987 という6バイトのデータを想定します。 上でも書きましたが、これは"123987"という「6文字」を示すのではない点にご注意ください。 あくまで、1バイト目は1という「値」で、2バイト目は2という「値」です。 この 123987 の6バイトを2進数で表記するとこうなります。 今回は、2進数の理屈については説明しませんので、「こういうもの」とお考えください。  1= 00000001  2= 00000010  3= 00000011  9= 00001001  8= 00001000  7= 00000111 この6バイトを一気に書くとこうなります。 ※以降の2進数表記では読みやすさを優先して途中に空白を空けています。  00000001 00000010 00000011 00001001 00001000 00000111 これをメールに書けばいいわけです。 これで万事解決...でしょうか? さすがにコレ、長すぎませんか? だって、6バイトのデータを送るだけで、6x8=48バイトいるんですよ。 いや、送るデータが6バイトだったらいいですよ。でも60KBなら8倍の480KB、6MBだったら48MBになる計算です。さすがにマズくないですか? というわけでもっと効率の良い方法を考えてみます。

6. 8進数にすると効率は一気に3倍!

さすがに2進数のままではあまりに効率が悪いので、もう少し改善しましょう。 例えば、上のデータ列を3ケタづつ区切って1文字にするのはどうでしょうか?実はこれ8進数といってコンピュータ世界では一時期(1970年代くらいまで)よく使われていた表記方法でした。 この変換ルールは次の通りです。  000 → 0  001 → 1  010 → 2  011 → 3  100 → 4  101 → 5  110 → 6  111 → 7 これに従って変換するとこうなります。  00000001 00000010 00000011 00001001 00001000 00000111  ↓(3ケタづつに区切り直し)  000 000 010 000 001 000 000 011 000 010 010 000 100 000 000 111  ↓(上記のルールで置換え)  0 0 2 0 1 0 0 3 0 2 2 0 4 0 0 7 なんと、さっきまで48バイト必要だったのが、1/3の16バイトまで減りました。 変換方式によって、ずいぶん効率良くなることがわかります。 では、もっと効率良くする方法はないものでしょうか?

7. Base64

ここで登場するのが、Base64(ベースろくよん)という変換方式です。 これは添付ファイルのルールを決めているMIME(マイム)と同時に決められた方式で6ビットを1文字に置き換える方式で、先ほどの方式よりさらに1/2までデータの圧縮が可能です。 やり方としては、ほぼ8進数の時と同様ですが、今度は64種類の文字を使います。 英大文字26種+英小文字26種+数字10種+記号(+と/)2種=64種となります。 その変換ルールは次の通りです。  000000 → A  000001 → B  000010 → C   :  000111 → H  001000 → I   :  010000 → Q   :  011001 → Z  011010 → a  011011 → b   :  100000 → g   :  110011 → z  110100 → 0   :  111101 → 9  111110 → +  111111 → / 8進数と同様にこれも変換してみましょう。  00000001 00000010 00000011 00001001 00001000 00000111  ↓(6ケタづつに区切り直し)  000000 010000 001000 000011 000010 010000 100000 000111  ↓(上記のルールで置換え)  0 Q I C B Q g H いかがでしょうか。2進数表記なら48バイト、8進数表記でも16バイトだったものがわずか8バイトにまで圧縮できました! このBase64はデビューが1996年と結構古いのですが、今もメールの添付ファイルでは必ずと言っていいほど使われています。

8. とはいえ、膨らむのは事実。

Base64は非常に効率の良いエンコーダ(変換ルール)なのですが、そうはいっても元データよりは効率が悪くなります。 思い出してください。最初に送りたかったのは 123987 という6バイトのデータです。 ですが、Base64でエンコードした結果は 0QICBQgH という8バイトになっています。 元データは6バイト、エンコード後が8バイトです。 つまり、元データから見ると4/3、即ち1.3倍強に膨らんでいます。 これが送れるはずの添付ファイルがサイズオーバとなる原因です。 冒頭で書いた5MBまで送れるサービスの場合、3MBのファイルなら、3×(4/3)=4MBになりますからOKで、4MBなら4×(4/3)=16/3=5.333MBになるのでアウト、というわけです。 これにメール本文なども必要ですので、実際に添付できるのはもう少し小さなサイズになるでしょう。

9. まとめ

メールを送付する時に、添付ファイルのサイズは送信可能サイズを越えていないのに「大きすぎる」と言われてしまう場合があります。 これは、添付ファイルをメールで送信できる文字に変換する時にどうしてもサイズが大きくなってしまうためです。 メールでは添付ファイルのエンコードにBase64を使います。この方式は非常に優れているのですが、それでも元データより1.3倍強に膨らんでしまいます。 それでも送付したい添付ファイルがある場合は、いくつかの方法があります。 GoogleドライブやMicrosoftのOneDrive、AppleのiCloudといったサービスを利用している場合は、送りたいファイルのURLを使ってファイルを共有できます。(パスワード設定されないので、機密性の高いファイルは要注意) また、ファイル預りサービスやファイル転送サービスと呼ばれるサービスもいろいろとあります。こういったサービスでは有効期限の設定やパスワードの有無も設定できますので、うまく利用したいものです。 ずっと前、こういったファイル共有サービスがなかった時代は、大きなファイルを複数に 分割してメール送付することもありましたが、現在ではそんなことをわざわざする必要はないでしょう。 今回は、メールにファイルを添付すると送付時にはそのサイズが膨らんでしまう理由をお話しました。 次回もお楽しみに。

前号: No 371 / 次号: No 373 / 一覧(note.com)へ / ブログページに戻る