LoginSignup
17
21

More than 5 years have passed since last update.

mail()関数に渡す本文の改行コードはCRLF?LF?

Posted at

疑問に思ったきっかけ

Phalcon とメールとテンプレートと

PHP BLTというイベントでの発表の一つ
大枠はPhalconの話であるが、メール送信時の改行コードの扱い方についての話があった。

以前、mail()関数を使ってメール送信で問題が起こり、同じような方法で回避した覚えがある。
気になったので調べてみようと思った。

まずはマニュアルを見てみる

PHP: mail - Manual

bool mail ( string $to , string $subject , string $message [, string $additional_headers [, string $additional_parameters ]] )

message

送信するメッセージ。

改行コードは CRLF (\r\n) となります。各行の長さは 70 文字を超えては いけません。

additional_headers(オプション)

メールヘッダの最後に挿入される文字列。

通常、これは追加のヘッダ(From、Cc、Bcc)のために用いられます。 複数のヘッダを追加する場合は CRLF(\r\n)で区切ります。 外部からのデータを用いてヘッダを組み立てる際には、想定外のヘッダが注入されることを防ぐための処理が必要です。

このように、ヘッダも本文もCRLFで改行をするようにと書いてある。

実装を見てみる

PHP5系と7.0.0とで大きな違いはないため、7.0.0のソースを見てみます
mail.c at php-7.0.0

sendmailコマンドのプロセスを立て、それに対してヘッダ・本文の情報を出力している(399行目から)

part-of-mail.c
        fprintf(sendmail, "To: %s\n", to);
        fprintf(sendmail, "Subject: %s\n", subject);
        if (hdr != NULL) {
            fprintf(sendmail, "%s\n", hdr);
        }
        fprintf(sendmail, "\n%s\n", message);
        ret = pclose(sendmail);

To や Subject、additional_headersの後、messageの前後の改行はLFである。
つまり複数のadditional_headersや複数行のmessageの改行をCRLFにすると、LFのみとCRLFが混ざった文字列をsendmailコマンドに渡すことになる。

実践

LFのみで改行した場合、CRLFで改行した場合の2通りを試してみた。

検証環境

PHP : 5.5.29
MTA : Postfix 2.6.6

LFのみで改行

mail-lf.php
<?php
mail(
    'to@example.com',
    'Test Subject',
    "row1\nrow2\nrow3",
    "From: from@example.com\nX-Mailer: hoge mail",
);
To: to@example.com
Subject: Test Subject
X-PHP-Originating-Script: 5000:mail-lf.php
From: from@example.com
X-Mailer: hoge mail

row1
row2
row3

LFのみで改行して、特に問題は見られない

CRLFで改行

mail-crlf.php
<?php
mail(
    'to@example.com',
    'Test Subject',
    "row1\r\nrow2\r\nrow3",
    "From: from@example.com\r\nX-Mailer: hoge mail",
);
To: to@example.com
Subject: Test Subject
X-PHP-Originating-Script: 5000:mail-crlf.php
From: from@example.com
X-Mailer: hoge mail

row1

row2

row3

CRLFで改行をすると、本文に余計な改行が入る。
ヘッダは問題なし

LFのみで改行するほうが正しいのでは?

考察とまとめ

マニュアルには次のような記述がある。

注意:

メッセージが受信されなかった場合には、LF(\n)のみを使ってみてください。 Unix の MTA の中には、自動的に LF を CRLF に変換してしまう もの (有名なところでは、» qmail など) があります(もし CRLF を利用していた場合、CR が重複してしまいます)。 ただし、これは最後の手段です。というのも、これは » RFC 2822 に違反しているからです。

MTAによって、改行コードを変えるなどの対応が必要な場合があるらしい。
今回、Postfixでしか検証をしていない。他のMTA、例えばSendmailであれば結果は違うかも?
要検証

sendmailコマンドを使わずに、PHPからSMTPのリクエストを送信するような場合にはCRLFで改行する必要はあると思う。
sendmailコマンドを使う(mail()関数を使う)場合には、改行が意図した通りになされているか確認したほうが良い。

もっと時間のある時に、詳細に調べたい。

17
21
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
17
21