Socket を使用したメール送信 - 続き 著者: limodou 以前、Web サーバーが mail() 関数をサポートしていない問題を解決するために、ソケット プログラミングを使用してメールを送信する方法を紹介する記事を書きました。私のテスト後は機能します。ただし、多くのフリーメールプロバイダー (263、163、および近々 Sina から始まります) が SMTP 機能に認証機能を追加し、元のメール送信クラスが使用できなくなりました。対応する SMTP フォローアップ RFC を研究し、多くの実験を行った結果、最終的に成功しました。そこで緊急に皆様にご紹介させていただきます。 SMTP 認証機能の概要 SMTP 認証機能については、明確に説明できないため、ここでは詳しく説明しません。詳細については、[RFC 2554] 仕様を参照してください。 SMTPの認証機能は主にAUTHコマンドが追加されます。 AUTH コマンドには多くの用途があり、多くの認証メカニズムがあります。 AUTHがサポートする認証機構には主にLOGIN、CRAM-MD5[注1]などが含まれます。 LOGIN は、263 や Sina など、ほとんどの無料電子メール サーバーでサポートされている必要があります。 Sina は CRAM-MD5 メカニズムもサポートしています。認証メカニズムは通常、電子メールが実際に送信される前にのみ実行され、実行する必要があるのは 1 回だけです。認証に成功すると、通常どおりメールを送信できます。原理はチャレンジ-レスポンスです。つまり、サーバーはクライアントに応答を求めるコマンドを送信し、クライアントはサーバーから送信された情報に基づいて応答します。応答が渡された場合、認証は成功し、プロセスを続行できます。 。この2つの作品について簡単に紹介します。 S: サーバーによって返されたことを意味し、C: クライアントによって送信されたことを意味します。ログイン もっとシンプルになるはずです。パスワード応答プロセスは次のとおりです。 1 C: AUTH LOGIN 2 S: 334 dXNlcm5hbWU6 3 C: dXNlcm5hbWU6 4 S: 334 cGFzc3dvcmQ6 5 C: cGFzc3dvcmQ6 6 S: 235 1 クライアントの認証指示をサーバーに送信します。 2 サーバーは Base64 でエンコードされた文字列を返し、成功コードは 334 です。エンコードされた文字列は「username:」にデコードされ、クライアントがユーザー名を送信する必要があることを示します。 3 クライアントは、base64 でエンコードされたユーザー名 (ここでは「username:」) を送信します。 4 サーバーは Base64 でエンコードされた文字列を返し、成功コードは 334 です。エンコードされた文字列は「password:」にデコードされ、クライアントがユーザー パスワードを送信する必要があることを示します。 5 クライアントは、base64 でエンコードされたパスワード (ここでは「password:」) を送信します。 6 成功後のサーバーの戻りコードは 235 で、認証が成功し、電子メールを送信できることを示します。 LOGIN 認証の場合、ユーザー名とパスワードは実際には Base64 でエンコードされ、サーバーの要件に応じて個別に発行されます。 (私の考えでは、base64 は公的エンコーディング標準であるため、あまり保護されません。) CRAM-MD5 のメカニズム CRAM-MD5 のメカニズムについては、[RFC 2195] 仕様を参照してください。詳細は説明しません。ここ。 。主にパスワード応答メカニズムを通じて、サーバーは乱数、タイムスタンプ、サーバー アドレスで構成され、base64 でエンコードされた情報文字列を送信します。それを受信したクライアントは、ユーザー名、スペース、ダイジェストで構成される文字列を送信し、base64 でエンコードします。概要は MD5 アルゴリズムを通じて取得されます。このメカニズムでは、サーバーとクライアントが同じ暗号化文字列を持っている必要があります。クライアントがダイジェストを送信した後、サーバーはその有効性を検証し、成功すると 235 を返します。 メールサーバーがどの認証をサポートしているかを確認するにはどうすればよいですか? SMTP [RFC 821] では、メールサーバーへの接続に成功した後の最初のコマンドは通常「HELO」です。ただし、認証をサポートするメールサーバーでは、最初のコマンドを「EHLO」に変更する必要があります[注 2]。コマンドが成功すると、263 が返されます。 EHLO hello 250-smtp.263.net [Note 3] 250-PIPELINING 250-SIZE 10240000 250-ETRN 250-AUTH LOGIN 250 8BITMIME 263 が LOGIN をサポートしていることがわかります。認証。もちろん、メールサーバーが何であるかをすでに知っている場合は自動的に判断する必要はありませんが、知らない場合は返信結果を分析する必要があります。ただし、ほとんどのメール サーバーは最も単純な LOGIN メソッドをサポートしています。 さて、前に書いたsendmail.class.php3の修正を始めましょう。しなくても問題ありません。sendmail.class.php3 のパッケージ ファイルはこの記事の最後に記載されているので、ダウンロードできます。例については、この記事を参考に自分で書きました。 sendmail.class.php3 を変更する ここでは、包括的な分析ではなく、変更の重要なポイントのみを説明します。 まず、誰もが最初にアイデアを持てるように、sendmail.class.php3 のアイデアを確認しましょう。 sendmail.class.php3 には、次の 4 つの関数があります。 send_mail クラスのコンストラクターは、情報の初期化に使用されます。 send メール送信関数は、socket コマンドを実行し、メールを送信します。 do_command コマンド実行関数は、smtp コマンドを実行します。結果 show_debug デバッグ情報表示関数 まず、ユーザはクラスのコンストラクタを呼び出し、必要なパラメータを初期化します。 SMTP サーバー アドレス ($smtp)、ウェルカム メッセージ ($welcome)、デバッグ情報を表示するかどうか ($debug) など。同時に、最後に実行されたコマンド ($lalast)、最後の応答メッセージ ($lastmessage)、ポート番号 ($port=25) など、いくつかの内部変数を初期化する必要があります。 次に、ユーザーは電子メール情報を生成し、send() 関数を呼び出して電子メールを送信します。 send() 関数では、SMTP 仕様に従って、1 つのコマンドが次々に実行されます (詳細については、前回の記事を参照してください)。コマンドを実行するときは、 do_command() を呼び出すことで実装されます。 do_command() の実行中にエラーが発生した場合、プログラムは直ちに戻ります。そうでない場合は、下方向に実行を続けます。デバッグ情報表示フラグが設定されている場合、コマンドが送信され、その情報が応答されたときに、 do_command() はデバッグ情報を返します。 さて、これで誰もがその操作を理解できました。これを変更する方法を説明します。 コンストラクタ(send_mail)の変更 従来のsend_mailクラスは認証機能をサポートしていないため、先に認証情報を追加する必要があります。 $auth、$authuser、$authpasswd の 3 つのパラメータが追加されました。 $authは認証機能を使用するかどうかを示すフラグです。 $authuser と $authpasswd は、対応するメール サービス プロバイダーの要件に従って、たとえば 263 は Pop3 と一致します。ほとんどの人にとっても同じはずです。このように、クラスの内部変数テーブルの後に、$auth、$user、$passwd の 3 つの内部変数を追加する必要があります。 送信関数(send)を修正し、送信コマンドHELOを送信EHLOに変更します。同時に、認証処理が必要かどうかを判断する必要があります。 // ESMTP EHLO コマンドをサポートするように変更します if($this->auth) { $this->lastact="EHLO " } else $this->lastact ="HELO "; つまり、認証処理が必要な場合は EHLO コマンドが送信され、そうでない場合は HELO コマンドも送信されます。 次に、認証処理を追加します。 //2000.02.28 認証処理を追加します if($this->auth) { $this->lastat="AUTH LOGIN" " 。 "; if(!$this->do_command($this->lafact, "334")) { fclose($this->fp); return false; } //base64 でエンコードされたユーザー名を返します $this-> lastact=base64_encode($this->user) " "; if(!$this->do_command($this->lastat, "334")) { fclose($this->fp); return false; } //base64 でエンコードされたパスワードを返します $this->lastat =base64_encode($this->passwd) 。 "; if(!$this->do_command($this->lafact, "235")) { fclose($this->fp); return false; } } AUTH LOGIN メカニズムである CRAM-MD5 のみが機能することに注意してください。ここでは実装されていません。デフォルトでは、最初はユーザー名を要求し、2 回目はパスワードを要求します。オリジナルのコマンド実行関数 (do_command) を変更します。応答文字列が複数行の場合、関数は状況を表示できません。 : /* 2000.02.28 に変更され、返された情報が完全に表示されるようになりました $this->lastmessage = fgets ( $this->fp, 512 ); show_debug($this->lastmessage, "in"); */ while (true) { $this->lastmessage = fgets ( $this->fp, 512 ); in"); if(($this->lastmessage[3]= = ) or (empty($this->lastmessage))) Break; } このようにして、クラスが変更されました。send_mail クラスをテストします。以下はレターを送るために書いた小さなテストプログラムですが、安全上の理由から、ユーザー名とパスワードには実際の情報は使用しません。テストしたい場合は、次のとおりです。 php): include("sendmail.class.php3"); $sendmail=new send_mail("smtp.263.net", true, "username", "password", "hello", true); $sendmail->send("toemail, "fromemail", "test", "This is a test. !"); ?> 結論 263 のテストは非常にスムーズに進み、比較的高速でした。しかし、Sina はタイムアウトが発生したり、送信できても受信できなかったりするため、なかなか成功しません。 注: SMTP の送信にはユーザー名とパスワードが必要であるため、ほとんどの SMTP 認証では、pop3 と同じユーザー名とパスワードが使用されます。したがって、この方法を使用する場合は、ユーザー名とパスワードをプログラムに書き込み、サーバーにアップロードすることができます。しかし、そうするのは安全ではありません。情報はサーバー上に配置され、対応する復号化された情報もサーバー上に配置されるため、暗号化は必ずしも使いやすいとは限りません。私の提案は、他人に知られても怖がらないように、クレジット送信専用のメールボックスを申請することです。 このプログラムがお役に立てば幸いです。 sendmail.class.php3 ダウンロード。 添付: 関連 RFC RFC 1869 SMTP サービス拡張 RFC 2195 IMAP/POP AUTHorize 拡張 (CRAM-MD5 に関する手順を含む) RFC 2222 簡易認証およびセキュリティ層 RFC 2554 認証用の SMTP サービス拡張 --------- -- ------------------------------------------------ -- ------------------- [注 1] CRAM=Challenge-Response Authentication Mechanism パスワード応答認証機構 MD5 は、主に RSA、PGP 中間で使用されるダイジェスト アルゴリズムです。 [注 2] EHLO の説明については、[RFC 1869] を参照してください。 [注 3] メールサーバーの応答文字列において、応答コードの後にスペース ( ) が続く場合は応答文字列が 1 行であることを意味し、マイナス記号 (-) が続く場合は複数行であることを意味します。 、応答コードの最後の行の後にはスペース ( ) が続きます。 この記事の所有権は limodou に属します。転載したい場合は、この情報を保管してください。 注: sendmail.class.php3 のダウンロード アドレス: http://www.zphp.com/files/sendmail.class