レガシーなMailerにメールを送信する際のノウハウを全てまとめる。

業務で対応しなければいけなくなったのだが、ガラケーギリギリの世代の自分にはハマりポイントが多すぎた。
逆に、古きコードを書くいい経験になったかもしれない。

要件

  • HTMLメールの送信。
  • HTMLメール非対応のものでも表示できるようにする。
  • HTMLメールはスタイル適用。
  • WindowsのデフォルトのMailer「メールアプリ」にも対応。

今回の案件は環境がPHPでしたのでPHPコードで解説。

HTMLメールの送信

<?php 
    mb_language("japanese"); //日本語に設定。
    mb_internal_encoding("UTF-8"); //UTF-8に設定。

    $from = "hogehoge@gmail.com"; //送信元
    $to = "hugahuga@gmail.com"; //宛先
    $subject = "おはよう"; //件名

    $today = date("Y/m/d"); //今日の日付を取得

    $html_body = <<< EOM //ヒアドキュメントの開始
<html>
<head>
<meta http-equiv="Content-Type" content="text/html" >
<meta lang="ja">
<meta charset="ISO-2022-JP">
<meta name="viewport" content="width=device-width,initial-scale=1">
</head>
<body>
    <h1>おはよう</h1>
    <p>{$today}です</p>
    <p>今日もいい1日にしましょう</p>
</body> 
EOM; //ヒアドキュメントの終了

    $headers = '';
    $headers .= 'MIME-Version: 1.0' . "\r\n";
    $headers .= 'Content-Type: text/html; charset=iso-2022-jp' . "\r\n";
    $headers .= 'Content-Transfer-Encoding: quoted-printable' . "\r\n";
    $headers .= "From: " . $from . "\r\n";

    $subject = mb_convert_encoding($subject, "iso-2022-jp"); //件名をJISに変換

    $message = '';
    $message .= quoted_printable_encode(mb_convert_encoding($htmlBody, 'iso-2022-jp', 'UTF-8')) . "\r\n"; //HTMLメールの本文をJISに変換したのちにquoted-printableに変換

    mb_send_mail($to, $subject, $message, $headers);
?>

基本的なコードでできる。
エンコードのところだけ公式を見ながら実装した。

HTMLメールにスタイルを適用

<?php 
    mb_language("japanese"); //日本語に設定。
    mb_internal_encoding("UTF-8"); //UTF-8に設定。

    $from = "hogehoge@gmail.com"; //送信元
    $to = "hugahuga@gmail.com"; //宛先
    $subject = "おはよう"; //件名

    $today = date("Y/m/d"); //今日の日付を取得

    $html_body = <<< EOM //ヒアドキュメントの開始
<html>
<head>
<meta http-equiv="Content-Type" content="text/html" >
<meta lang="ja">
<meta charset="ISO-2022-JP">
<meta name="viewport" content="width=device-width,initial-scale=1">
</head>
<body>
    <h1 style="text-align: center;">おはよう</h1>
    <p>{$today}です</p>
    <p style="font-size: 12px;">今日もいい1日にしましょう</p>
</body> 
EOM; //ヒアドキュメントの終了

    $headers = '';
    $headers .= 'MIME-Version: 1.0' . "\r\n";
    $headers .= 'Content-Type: text/html; charset=iso-2022-jp' . "\r\n";
    $headers .= 'Content-Transfer-Encoding: quoted-printable' . "\r\n";
    $headers .= "From: " . $from . "\r\n";

    $subject = mb_convert_encoding($subject, "iso-2022-jp"); //件名をJISに変換

    $message = '';
    $message .= quoted_printable_encode(mb_convert_encoding($htmlBody, 'iso-2022-jp', 'UTF-8')) . "\r\n"; //HTMLメールの本文をJISに変換したのちにquoted-printableに変換

    mb_send_mail($to, $subject, $message, $headers);
?>

styleタグを読み取ってくれないMailerがあるのでinline-styleで記述していく。
バグの元になるので変換サービスを利用するのをオススメする。
https://inlinestyler.torchbox.com/

レガシーなMailerに対応

今回の例のメールなら変更はいらないが、レガシーなMailerに対応するためにTable LayoutでHTMLメールの本文を記述する

HTMLメール非対応のMailerに対応

<?php 
    mb_language("japanese"); //日本語に設定。
    mb_internal_encoding("UTF-8"); //UTF-8に設定。

    $from = "hogehoge@gmail.com"; //送信元
    $to = "hugahuga@gmail.com"; //宛先
    $subject = "おはよう"; //件名

    $today = date("Y/m/d"); //今日の日付を取得

    $html_body = <<< EOM //ヒアドキュメントの開始
<html>
<head>
<meta http-equiv="Content-Type" content="text/html" >
<meta lang="ja">
<meta charset="ISO-2022-JP">
<meta name="viewport" content="width=device-width,initial-scale=1">
</head>
<body>
    <h1 style="text-align: center;">おはよう</h1>
    <p>{$today}です</p>
    <p style="font-size: 12px;">今日もいい1日にしましょう</p>
</body> 
EOM; //ヒアドキュメントの終了

    $text_body = "";  //テキストメールの本文の作成
    $text_body .= "おはよう\r\n";
    $text_body .= "{$today}です\r\n";
    $text_body .= "今日もいい1日にしましょう";

    $boundary = "--" . uniqid(rand(), 1); //boundaryをランダムに作成

    $headers = '';
    $headers .= 'MIME-Version: 1.0' . "\r\n";
    $headers .= 'Content-Type: multipart/alternative; boundary="' . $boundary . '"' . "\r\n"; //Content-Typeをマルチパートに変更
    $headers .= 'Content-Transfer-Encoding: quoted-printable' . "\r\n";
    $headers .= "From: " . $from . "\r\n";

    $subject = mb_convert_encoding($subject, "iso-2022-jp"); //件名をJISに変換

    $message = '';
    $message .= '--' . $boundary . "\r\n"; //境界を明記
    $message .= 'Content-Type: text/plain; charset=iso-2022-jp' . "\r\n"; //Content-Typeをtext/plainに設定
    $message .= 'Content-Disposition: inline' . "\r\n";
    $message .= 'Content-Transfer-Encoding: quoted-printable' . "\r\n";
    $message .= "\r\n";
    $message .= quoted_printable_encode(mb_convert_encoding($textBody, 'iso-2022-jp', 'UTF-8')) . "\r\n"; //テキストメールの本文をJISに変換したのちにquoted-printableに変換
    $message .= "\r\n";
    $message .= '--' . $boundary . "\r\n"; //境界を明記
    $message .= 'Content-Type: text/html; charset=iso-2022-jp' . "\r\n"; //Content-Typeをtext/htmlに設定
    $message .= 'Content-Disposition: inline' . "\r\n";
    $message .= 'Content-Transfer-Encoding: quoted-printable' . "\r\n";
    $message .= "\r\n";
    $message .= quoted_printable_encode(mb_convert_encoding($htmlBody, 'iso-2022-jp', 'UTF-8')) . "\r\n"; //HTMLメールの本文をJISに変換したのちにquoted-printableに変換
    $message .= '--' . $boundary . "--\r\n"; //マルチパートの終了を明記

    mb_send_mail($to, $subject, $message, $headers);
?>

HTMLメールに対応してないMailerのために同時にテキストだけのメールを送信するようにする。
Content-Type: multipart/alternative;にすることでマルチパートの記述が可能になる。
boundary(境界)を設定することで、「ここからここまではこの”Content-Type”」とできるので、HTMLメールとテキストメールが同時に送信できるようになる。
HTMLメールに対応してないMailerとしてEdMaxがあるのでテスト用に使用した。
http://www.edcom.jp/edmaxtop.html

最後に

今回は記述しなかったが、実装した際にはもう1つ抽象的なクラスを作った。
また、FlexBoxという神ができてからフロントに関わったためTable Layoutにも不慣れで多少苦労した。
もしかしたら今後二度と触れない要件かも知れなかったので経験できてよかった。

あ、あと初投稿なのでフォロー、いいねお願いします笑
Twitter→ https://twitter.com/issueee09
note→ https://note.mu/issueee09

Sign up for free and join this conversation.
Sign Up
If you already have a Qiita account log in.