# MIME
HTTPレスポンスは、HTMLだけでなく画像、動画、JSON、PDFなど様々な形式のデータを扱います。
ブラウザはどのようにして「このデータがどういう形式なのか」を判定しているのでしょうか。
その答えがMIME(Multipurpose Internet Mail Extensions)です。
## MIMEとは
MIMEは、"Multipurpose Internet Mail Extensions"の略で、もともとは電子メールで様々な形式のデータを扱うために策定された規格です。
MIMEでは大きく2つの部分で活躍します。
- データの形式を示す『コンテントタイプ』の表現
- データのエンコード方式
元来、電子メールはASCIIコード(7ビット)によるテキストデータのみを扱うように設計されていました。
しかし非英語圏(非ASCII圏)では文字コードが異なっており、そのままでは送ることができません。
また、画像や音声、動画といったバイナリデータも送ることができません。
そこで、MIMEという拡張を考案し、送ろうとするテキストがどのようなモノで、どのようなエンコード方式を使っているのかと言うことを明示できるようにしました。
```{note}
非ASCII圏の文字コードがまったくメールに使えなかったというわけではありません。
7ビット(8ビット目がパリティにより操作されてしまう)ことを前提とした(すなわち8ビット目を使用しない)文字コードであれば送ることが仕組み上可能でした。
そのため、日本においてはJUNETコードという日本語用の文字コード体系を用いて、後のJIS標準の文字コードという形を取りました。現在では国際的な枠組みで使われるものとなっており、ISO-2022-JPとして知られています。
ただし、非ASCII圏のメールは、両者(送信者・受信者)の合意で同じ文字コードが認識できないと表示できないという問題が生じます。
そこでMIMEにおいて文字コードを明示的に渡すという仕組みができたわけです。
```
```{note}
画像やプログラムといったバイナリコードがまったくメールで送れなかったわけではありません。
非ASCII圏の問題と同様に「7ビットの範囲内で表現できる」エンコードを用いればかなり強引ですが送ることは可能でした。
日本では、`ish`というプログラムがインターネットの黎明期やそれ以前から使われており、バイナリデータを7ビットの範囲内で表現するエンコード方式を用いていました。
さらに`ish`では、通信環境が不安定であることを考慮して、データのチェック機能やある程度の復元機能などが備えられていました。
```
### コンテントタイプ
コンテントタイプ(Content-Type)は、データの形式を表すための文字列です。
HTTPにおけるリクエストやレスポンスのヘッダで用いることで、データの形式を明示的に示す事ができます。
また、ついでに近いですが文字コードの指定も行えるようになっています。
コンテントタイプの指定は、ヘッダを用いて、以下のような形式で行います。
```
Content-Type: text/plain
```
値(`text/plain`)の部分がコンテントタイプを示しています。値はスラッシュ(`/`)で区切られた二つの部分で構成されており、大きく『メディアタイプ』と『サブタイプ』に分かれています。
- メディアタイプはデータの大雑把な形式を示します
- text: テキストファイル
- image: 画像
- audio: 音声
- video: 動画
- application: アプリケーション
- それ以外の特殊なものとして、`x-`で始まるものがあります。
- サブタイプはそれぞれのメディアタイプの中で、実際のファイル形式を示すものとなっています。
- 例えばテキスト(text)であれば、以下のような形式が主なものとして使われます。
- text/plain: プレインテキスト(そのまま出力)
- text/html: HTML文書
- text/css: CSSスタイルシート
- text/javascript: JavaScriptファイル
- 画像(image)であれば、以下のような形式が主なものとして使われています。
- image/jpeg: JPEG画像
- image/png: PNG画像
- image/gif: GIF画像
- image/svg+xml: SVG画像
このように、ヘッダに含まれているMIMEコンテントタイプを用いることで、受け取る側(主にブラウザ)は、ボディ部分のデータをどのように扱えばいいのかを判断できるようになっています。
```{note}
Internet Explorerの互換性問題について(筆者(佐藤)の主観)。
その昔、Microsoftは、自社製OS(Windows)に自社製のブラウザとして"Internet Explorer"というものをバンドルさせており、(選択肢を知らない)ユーザー達は、最初から使えるということでこのブラウザが普及しました。企業では『余計なソフトを入れる必要が無い』『社員統制のために都合が良い』といったことから、Internet Explorerを使い続けることが多かったようです。
このブラウザでは、MIMEコンテントタイプを正しく解釈せず、ファイルの拡張子に応じて勝手に解釈してしまうという問題がありました。たとえば、`text/html`で送られてきたファイルであっても、拡張子が`.txt`であればプレインテキストとして扱い、`.html`であればHTMLとして扱うというようなことをしていました。
拡張子とコンテントタイプをきちんとあわせれば良いという話ではあるのですが、企業での利用においては、ファイルの拡張子を勝手に変えられない(セキュリティポリシーで禁止されている)ことも多く、結果として正しいコンテントタイプを送っても正しく解釈されないという問題が発生しました。
この問題は、後々まで引きずることとなり、Webアプリケーションの開発においては、Internet Explorerを考慮した実装を行う必要がありました。たとえば、HTMLを返すAPIであっても、拡張子を`.html`にしておくとか、JavaScriptを返すAPIであっても拡張子を`.js`にしておくといったことが必要でした。
Internet Explorerは、さらにWindows上でしか機能しないような機能・技術(ActiveXやVBScript、JScript)を組み込み、意図的にそれらを使わせるようにエンジニアに流布したことから、Web標準を無視した実装が横行することとなりました。
なお現在は開発が終了しており、Microsoft Edgeというブラウザに(ほぼ完全に)移行した状態となっています。
```
実際にコンテントタイプを確認してみましょう。
curlコマンドでは、`-I`オプションを付けることでヘッダのみを取得することができます。
```bash
$ curl -I https://www.kobedenshi.ac.jp/
HTTP/2 200
date: Wed, 03 Sep 2025 06:09:54 GMT
server: Apache
x-cached: Wed, 03 Sep 2025 06:09:54 GMT
cache-control: max-age=300
expires: Wed, 03 Sep 2025 06:14:54 GMT
content-type: text/html; charset=UTF-8
```
レスポンスヘッダ部分に `content-type: text/html; charset=UTF-8` という部分があることがわかります。つまり「www.kobedenshi.ac.jpの`/`のコンテンツ」はHTMLであるということがわかりました。
また、`;`以降の `charset=UTF-8` という部分は、文字コードがUTF-8であることを示しています。
それ以外には、主要なWebブラウザに実装されている開発ツール({kbd}`F12`キー)を用いて、ネットワーク(Network)タブで確認することもできます。
```{figure} images/devtool.png
:width: 80%
開発ツールを用いたContent-Typeの確認例
```
ブラウザはこの情報をもとに、ボディ部分をHTMLとして解釈し、文字コードをUTF-8として扱うことができます。
画面表示を伴わないデータの送受信であれば、JavaScriptで直接データとして扱いやすいJSON(JavaScript Object Notation)形式でのやりとりが多く使われています。
JSONはAPIのところで使ったような可読化されたものとなっています。
```{literalinclude} src/api/users.json
:language: json
:caption: JSONの例
```
このようなデータのやりとりをする時には、`application/json`というコンテントタイプが使われます。
```{code-block}
:language: bash
:emphasize-lines: 5
$ curl -I localhost:5000/users/1
HTTP/1.1 200 OK
Server: Werkzeug/3.1.3 Python/3.13.5
Date: Wed, 03 Sep 2025 06:42:55 GMT
Content-Type: application/json
Content-Length: 33
Connection: close
```
### エンコード方式
非ASCII語圏の文字コードは、7ビットを意識しない文字コード(8ビット文字コード)が多いという国もあります。また、そもそも8ビットの範囲で文字が収まらない(日本語や中国語、ハングルなど)文字コードも存在します。1バイトで収まらないような言語圏では『マルチバイト』という形で連続する複数バイトの並びで文字コードを表現しています。
さらに、画像や音声といったものはバイナリデータとして8ビット全てを使った表現になっています。
これらをやりとりできるようにするために、ASCII(7ビット)の範囲に収まるように相互変換できる仕組みというのが制定され、2つのエンコーディング手法が登場しました。
- Base64: 3バイト(24ビット)を6ビットを単位とする4つに区分けし、それぞれ(10進数としては0〜63)に対する文字を割り当てる方式、仕組み上133%(4/3倍)に膨れ上がることとなります。
- Quoted-Printable: ASCIIで表現できないバイトを `=` に続けて16進数の文字列2文字に変換する方式。ヨーロッパ語圏で使われる「ほとんどASCIIで表現できるけど、時々非ASCII語圏が混ざる」というケースでは有効と考えられています。
- 例えばドイツ語の"Grüße"(グリュース、挨拶)は、ISO-8859-1であれば`Gr=FC=DFe`、UTF-8であれば`Gr=C3=BC=C3=9Fe`と表現されます。
Quoted-Printableは、非ASCIIの文字列は1バイトが4バイト(4文字)になるという非常に大きなペナルティがあるため、ほとんどASCII文字で表現できる場合には有効ですが、そうでない場合にはBase64を使うことが実情です。
また、バイナリファイルのエンコーディングもBase64が使われていることが多いです。
### 添付ファイル
メールでは添付ファイルを送る(本文+画像など)ことが求められるようになったため、MIMEでは添付ファイルを送るための仕組みも用意されています。
添付ファイルを送るためには、本文と添付データの区切りというものが必要です。
そこでMIMEではヘッダにおいて区切りのための文字列というものを指定できるようにしました(バウンダリ; boundary)。
各バウンダリではヘッダを付けることができ、Content-Typeを用いて添付ファイルの形式を指定したり、Content-Transfer-Encodingを用いてエンコード方式を指定したりできます。
また、Content-Dispositionを用いて、添付ファイルの名前や、本文に埋め込むのか添付ファイルとして扱うのかといったことを指定できます。
この仕組みを活かしたのがいわゆる『HTMLメール』です。
HTMLメールでは、本文にHTMLを入れることができ、画像も添付画像を利用するように設定することで、受信した内容をリッチに表現することができました。
またHTMLメールに対応できない環境のために通常のテキスト(Plain Text)も添付するということが行われました。
広告などでは見た目を向上させるという効果が期待されましたが、HTMLメールは容量が大きくなる(現在ほどメールボックス容量は多くなかった)ことや、HTMLメールにおける表現がセキュリティ的な問題をはらんでいることが多かったため、当初は忌避される傾向にありました。
その一方で、ここ数年(Webメールを使うことが多くなった)では、比較的HTMLメールも使われるようになっている模様です。