未分類

【PHP】qdsmtpをSTARTTLSに対応する

昔から運用しているサーバを移設することになりました。

メール送信にqdmailおよびqdsmtpを使用しています。

一部改修が必要なため、以下URLを参考にAUTH LOGINへ対応させました。

QdsmtpをAUTH LOGINに対応させる

AUTH LOGIN認証は、SMTPサーバーに対して「AUTH LOGIN」コマンドを送ります。

その後、ユーザー名とパスワードをBase64でエンコードして送ります。

実行するソースコード test.php


require_once('/include_dir/qdmail.php');
require_once('/include_dir/qdsmtp.php');

$mail = new Qdmail();
$mail -> errorDisplay( true );

$mail -> smtp(true);

$param = array(
    'host'=>'email-smtp.us-east-1.amazonaws.com',
    'port'=>  587 ,
    'from'=>'from@exapmle.com',
    'protocol'=>'SMTP_AUTH',
    'user'=> 'username',
    'pass' => 'userpass'
);

$mail -> smtpServer($param);

$message="メールの中身をここに書きます。";

$mail ->to('toadress@example.com','test');
$mail ->subject('メールのテスト');
$mail ->from('from@example.com');
$mail ->text($message);
$return_flag = $mail ->send();

実行結果抜粋


QdSmtp error: Unkown Error :status530 message:530 Must issue a STARTTLS command first on auth login

エラーが発生します。

auth loginはSTARTTLSを先に始めてくださいねという内容ですね。

今回は、SMTPサーバにAmazon SESを使用しています。

Amazon SESは全ての通信を暗号化(TLS)必要があるため、

上記のようなエラーが発生します。

解決策

qdsmtp.phpを改修し、STARTTLSに対応します。

変更と追加が必要な箇所だけ抜粋します。


    function sendBase( $data = null ,$protocol = null ){
        if( !is_null( $data ) ){
            $this->data = $data;
        }
        if( is_null( $protocol ) ){
            $protocol = $this->protocol_def;
        }
        switch($protocol){
            case 'POP_BEFORE'://POP3
                if( !$this->pop3() ){
                    return $this->errorGather('POP failure',__LINE);
                }
            case 'SMTP':
                if( !is_resource( $this->sock ) ){
                    $this->sock = $this->connect();
                }
                $this->sayHello();
                if( !$this->sendData() ){
                    return false;
                }
            break;
            case 'SMTP_AUTH':
                if(!is_resource($this->sock)){
                    $this->sock = $this->connect();
                }

                if( !$this->already_auth ){
                    $this->sayHello();
                    if( 0 === preg_match('/[\s-]AUTH\s+([^\r\n]*)\r?\n/is', implode($this->smtpLFC,$this->smtp_log) , $matches)){
                        return $this->errorGather('HOST:'.$this->smtp_param['HOST'].' doesnot suppoted SMTP AUTH Protocol',__LINE__);
                    }
                    //STARTTLSの処理追加
                    if( !$this->enableTLS() ){
                        $this->already_auth = false;
                        return $this->errorGather('STARTTLS Error',__LINE__);
                    }
                    stream_socket_enable_crypto($this->sock, true, STREAM_CRYPTO_METHOD_TLS_CLIENT);
                    //再度 EHLO hostname
                    $this->sayHello();
                    //暗号化有効にする
                    $mes = strtoupper( $matches );
                    $decide = null;
                    foreach($this->smtp_auth_kind as $auth){
                        if( false !== strpos( $mes , $auth ) ){
                            $decide = $auth;
                            break;
                        }
                    }
                    if( is_null( $decide ) ){
                        return $this->errorGather('HOST:'.$this->smtp_param['HOST'].' doesnot suppoted MY Abalable SMTP AUTH Protocol '.implode(' or ',$this->smtp_auth_kind),__LINE__);
                    }
                    $decide = strtolower( str_replace( '-' , '_' ,$decide ) );
                    if( !$this->{$decide}() ){
                        return $this->errorGather('Auth Error',__LINE__);;
                    }
                    $this->already_auth = true;
                }
                if( !$this->sendData() ){
                    $this->already_auth = false;
                    return $this->errorGather('Send Data Error or Auth Error',__LINE__);
                }
            break;
            case 'OVER_SSL':
            break;
            default:
            break;
        }
        return $this->errorGather();
    }
/*必要な関数だけ抜粋*/
    function enableTLS(){
        $items = array(
            array( 'STARTTLS' ,  null ),
            );
        list( $st , $mes , $com ) = $this->communicate($items);
        if(!$st){
            return 0;
        }
        return 1;
    } 

enableTLS関数を追加して、SendBase関数を変更しています。

改修前後のSMTPの通信の流れを示します。

改修前

改修後

まとめ

SMTPのいい勉強になりました。

qdmailをやめたかったですが、改修ボリュームが大きかったので

今回はqdsmtpを改修するに至りました。