PHPでメールに添付ファイルをつけて送る方法 | A Day In The Boy's Life

A Day In The Boy's Life

とあるエンジニアのとある1日のつぶやき。

以前に、「メール本文の1行の文字数制限 -PHPアプリ- 」という記事を書きましたが、今度は、PHPで添付ファイルを送る件について。

まぁ、PEARで用意されているMail_Mime とか使えばいいんでしょうけど・・・。


メールを送信する前提となる、サーバー上の設定は全て割愛します。

また、テストした環境はPHP4.3系です。


<?php
/**
* 利用するには
* $body_ : 送りたいメールの本文
* $attach_['filepath'][N] : サーバー上に保管されているファイルの絶対パス
* $attach_['filename'][N] : 添付ファイルの名前
* $toaddr_ : 送信先
* $subject_ : メールのタイトル
*
* を予めセットしておく
*/

// メールの本文
$body_ = "このメールは、
テストです。
";
// 送信する添付ファイル(サーバー上にあるファイルを指定)
$attach_ = array("filepath" => array("/tmp/document.txt"), "filename" => array("ドキュメント.txt"));

// 送信先(複数送る場合は、カンマ区切り)
$toaddr_ = "foo@hogehoge.com";

// 送信元
$from_addr = "bar@hogehoge.com";
// ヘッダにFromを追加
$headers_ .= "From: " . $from_addr;

// メールタイトル
$subject_ = "テストメール";

// メール本文中の境界線(文字データと添付データの)
// メールの中で使われないようなユニークなものであればなんでも良い
$mail_boundary = "---=_" . uniqid("Boundary") . "_" . uniqid("Next");

// メールの基本ヘッダ
$mail_header = "";
$mail_header .= "Mime-Version: 1.0\n";
$mail_header .= "Comments: System sent this mail\n";

// 添付ファイルがある場合に追加するヘッダ(複数パートからなるメールを送信する)
// 添付ファイルがない場合はいらない
$mail_header .= "Content-Type: multipart/mixed;boundary=\"" . $mail_boundary . "\"\n";
$mail_header .= "Content-Transfer-Encoding: Base64\n";

// メールの本文用ヘッダ
$mail_body .= "Content-Type: text/plain;charset=\"ISO-2022-JP\"\n";
$mail_body .= "Content-Transfer-Encoding: 7bit\n";
$mail_body .= "--" . $mail_boundary . "\n";

// 添付ファイルの情報を格納するボディ
$att_body = NULL;

// 添付ファイルの数だけ、添付ファイルの情報をメールの本文(BODY)に追加する
for ($i = 0; $i < count($attach_['filepath']); $i++) {

    if (file_exists($attach_['filepath'][$i]) && is_readable($attach_['filepath'][$i])) {

// 存在する場合は、指定のファイルを開き中身を取り出す
$fp = fopen($attach_['filepath'][$i], "r"); $buf = fread($fp, filesize($attach_['filepath'][$i])); fclose($fp); // 添付ファイルの中身をBASE64でエンコードし、適切に分割する $attach_bin = chunk_split(base64_encode($buf)); // 添付ファイルを本文(BODY)に追加する $att_body .= "--" . $mail_boundary . "\n"; $att_body .= "Content-Type: application/octet-stream;name=\"{$attach_['filename'][$i]}\"\n"; $att_body .= "Content-Transfer-Encoding: Base64\n"; $att_body .= "Content-Disposition: attachment;filename*=ISO-2022-JP'ja'{$attach_['filename'][$i]}\n"; $att_body .= "\n" ; $att_body .= $attach_bin . "\n" ; $att_body .= "\n" ; } } // メール本文(BODY)の終わりを示す文字列 $att_body .= "--" . $mail_boundary . "--\n" ; // メールの本文と添付ファイル部分を結合する // $body_ は実際に送りたいメールの内容を埋め込む $mail_body .= $body_; $mail_body .= "\n"; $mail_body .= $att_body; // メール本文をJISコードへ変換する $mail_body = mb_convert_encoding($mail_body, "JIS"); // メールの件名をエンコード $mail_subject = mb_encode_mimeheader($subject_, "JIS"); // 送信先 $mail_toaddr = $toaddr_; // メール送信 $send_flg = mail($mail_toaddr, $mail_subject, $mail_body, $mail_header); if ($send_flg === TRUE) { // 送信成功の場合 } else { // 送信失敗の場合 }

コードを見れば分かるように、今のメールの仕組みでは厳密に添付ファイルを送信する手段と言うものが定義されていません。

これは、文字データのみをやり取りする事を前提にメールの仕組みが設計されているからです。

添付ファイルを送る為には、メールの本文であるBODY部に無理やりそのデータをねじ込んで送る事になります。


その際に、メールの文字部分(プログラムの最初にしていた$body_)と、添付データ部分($att_body)の境界を定めておかなければなりません。

そのために、境界線($mail_boundary)を定義しています。

そして、このメールでは境界線を使って複数のパートに分けられていますよと受信したメーラ側にも認識させるために、ヘッダに「Content-Type: multipart/mixed;boundary=」と追加しているわけです。


添付ファイルがない場合は、複数パートに区切る必要も無いのでこれらのヘッダは必要ありません。

今回のプログラムでは、添付ファイルを送る前提で作りましたのでマルチパートのヘッダは絶対に出力されます。

汎用的に作るのであれば、その有無によってヘッダを制御する必要があります。

また、今回はメールの文字データの方に関してはなんら制御を加えていません。

前回の「メール本文の1行の文字数制限 -PHPアプリ- 」のようにメールの本文への制御も必要になってくるかと思います。


最終的には、PHPのmail()関数 に渡しているので詳細な仕様はそちらを確認してください。