amo-kです。phpでSMTPクライアント書きました~ 書いてみたきっかけ PHPだとmail()mb_send_mail()でメール送信できちゃうけどよくよく見てみると、SMTPコマンドのHELOコマンドやMAIL FROMコマンドに値を指定できないぽい。最後の引数に、MTAに渡すコマンドラインオプションを指定可能だが、これはMTAに依存するということだ。MAIL FROMコマンドの値を指定したくても、この最後の引数に指定するしかないということになる。 では、何処でHELOコマンドやMAIL FROMコマンドの値を設定しているかというと、php.iniのSMTPディレクティヴやsendmail_fromディレクティヴの値となる。(Windows版phpのみ)つまり、アプリケーションレベルでこれ等の値を指定したい場合に、明確に指定するIFが無いということだ。 あれやこれやと考える時間がもったいないので、この前HTTPクライアント書いたし、せっかくなのでSMTPクライアントも書いて見たw コード:
<?php
/**
 * SMTPクライアント
 */
class AN_SMTP extends AN_Base
{
    private $host;
    private $port;
    private $error_no;
    private $error_str;
    private $sock_ttl;
    private $to;
    private $from;
    private $subject;
    private $body;
    private $header;
    private $envelope_from;
    private $socket;

    /**
     * コンストラクタ
     *
     * @param String $host     SMTPサーバホスト名
     * @param String $port     SMTPサーバポート番号
     * @param String $sock_ttl ソケットタイムアウト値
     * @return なし
     */
    public function __construct($host, $port, $sock_ttl)
    {
        $this->host     = $host;
        $this->port     = $port;
        $this->sock_ttl = $sock_ttl;
    }

    /**
     * メール送信
     *
     * @param String $to            RCPT TO コマンド用
     * @param String $from          Fromヘッダ用($envelope_from省略時はMAIL FROMコマンドにも使用)
     * @param String $subject       Subjectヘッダ用
     * @param String $body          Subjectヘッダ用
     * @param String $header        任意のヘッダ
     * @param String $envelope_from MAIL FROMコマンド用
     * @return なし
     */
    public function mail($to, $from, $subject, $body, $header = "", $envelope_from = "")
    {
        if (!$to || !$from || !$subject || !$body)
        {
            throw new AN_Exception("引数が不正です。");
        }
        $this->to      = $to;
        $this->from    = $from;
        $this->subject = $subject;
        $this->body    = $body;
        $this->header  = $header;
        $this->envelope_from = $envelope_from ? $envelope_from : $from;

        $this->socketOpen();
        $this->sendSMTP();
    }

    /**
     * ソケット接続
     *
     * @param  なし
     * @return なし
     */
    private function socketOpen()
    {
        if (($this->socket = fsockopen($this->host, $this->port, $this->error_no, $this->error_str, $this->sock_ttl)) === false)
        {
            throw new AN_Exception("socket open error!");
        }
        $this->getReceiveMsg();
    }

    /**
     * SMTPコマンド送信
     *
     * @param  なし
     * @return なし
     */
    private function sendSMTP()
    {
        $this->sendSocketCommand(sprintf("HELO <%s>\r\n", $this->host));
        $this->sendSocketCommand(sprintf("MAIL FROM: <%s>\r\n", $this->envelope_from));
        $this->sendSocketCommand(sprintf("RCPT TO: <%s>\r\n", $this->to));
        $this->sendSocketCommand("DATA\r\n");
        $this->sendSocketCommand(sprintf("%s\r\n%s\r\n.\r\n", $this->getHeader(), $this->body));
    }

    /**
     * ソケット接続先サーバよりレスポンスメッセージ取得
     *
     * @param  なし
     * @return なし
     */
    private function getReceiveMsg()
    {
        if(($res = fgets($this->socket, 1024)) === false)
        {
            // クライアント応答通信エラー
            throw new AN_Exception("socket receive error!");
        }
        if(!preg_match("/(2|3)/", substr(str_replace("\r\n", "", $res), 0, 1)))
        {
            // サーバ応答通信エラー
            throw new AN_Exception("socket response error!");
        }
    }

    /**
     * ソケット接続先サーバへコマンド送信
     *
     * @param  String $command コマンド
     * @return なし
     */
    private function sendSocketCommand($command)
    {
        if (!$command)
        {
            throw new AN_Exception(sprintf("SMTPコマンドが不正です。: %s", $command));
        }
        fputs($this->socket, $command);
        $this->getReceiveMsg();
    }

    /**
     * ヘッダ文字列取得
     *
     * @param  なし
     * @return なし
     */
    private function getHeader()
    {
        $header  = "MIME-version: 1.0\r\n";
        $header .= sprintf("Date: %s\r\n",    $nowdate);
        $header .= sprintf("From: %s\r\n",    $this->from);
        $header .= sprintf("Subject: %s\r\n", sprintf("=?shift_jis?B?%s?=", base64_encode($this->subject)));
        $header .= $this->header;
        return $header;
    }
}
?>