WebSurfer's Home

""

Web アプリからメール送信

以下のようなことをしたくて、Web アプリからメールを送信するためのコードを実装してみました。 (まぁ、このホームページでは使い道はないのですが、勉強のためということで)

  • ユーザー登録(アカウントの作成)の際、メールアドレスを入力してもらい、自動生成したパスワードをメールで連絡する。
  • パスワードを忘れたユーザーのためにパスワード再生機能を設け、再生した新パスワードをメールで連絡する。

ASP.NET の CreateUserWizard, PasswordRecovery を使用すれば、 ほとんどコーディングレスで上記のような機能が実装できるというようなことが書いてあったんですが、 そう簡単にはいきませんでした。

どのように設定してもメールが送信できないので、プロトコルアナライザー (WireShark) を使って、 SmtpClient と SMTP サーバーのコマンド/レスポンスをキャプチャーして、どうなっているのか調べてみました。

SMTP コマンド/レスポンスのキャプチャー

上の画像は小さくて読みづらいかもしれませんが、LOGIN 認証手続きには入るものの、 AUTH login *********** というコマンドに対して、500 authentication failed というレスポンスが帰ってきて認証失敗に終わっているのが読めるでしょうか? (ちなみに、*********** の部分は、account または host\account を Base64 でエンコードしたものになります)

Outlook Express を使ってどうなっているか調べたところ、 AUTH LOGIN → 334 VXNlcm5hbWU6 → アカウント名 → 334 UGFzc3dvcmQ6 → パスワード → 235 Authentication successful 、とサーバーのレスポンスを待ってアカウント名とパスワードを送信する形になり認証に成功します。 当然ながら、メール送信は成功します。

結論として、(1) SmtpClient は AUTH SMTP は LOGIN しかサポートしていない。 (2) LOGIN 認証の方法は標準化されておらず、今回の例のように組合せによってはうまくいかない。 (3) SmtpClient は使用不可、ということになってしまいました。(^_^;)

やむを得ないので、古い形式で使用は推奨されてないようですが、System.Web.Mail.SmtpMail を使ってみたところ、こちらは SMTP 認証が問題なくでき、メールも送信されることがわかりました。 これで SMTP 認証ができないという問題は解決できます。

次の問題は、CreateUserWizard, PasswordRecovery のメール送信機能を、どのように System.Web.Mail.SmtpMail を使用した自作のコードに置き換えるかということです。 それについては、SendingMail イベントを処置するハンドラを作って、そこで CreateUserWizard, PasswordRecovery によるメール送信をキャンセルし、代わりに System.Web.Mail.SmtpMail を使用してメールを送信するようにしました。具体的には以下のような感じです。

protected void CreateUserWizard1_SendingMail(object sender, MailMessageEventArgs e)
{
  e.Cancel = true;
  SendEmail(e.Message);
}

protected void SendEmail(System.Net.Mail.MailMessage msg)
{
  System.Web.Mail.MailMessage mail = new System.Web.Mail.MailMessage();
  mail.To = msg.To[0].Address;
  mail.From = msg.From.Address;
  mail.Subject = msg.Subject;
  mail.Body = msg.Body;
  mail.BodyFormat = System.Web.Mail.MailFormat.Text;
  mail.Fields.Add("http://schemas.microsoft.com/cdo/configuration/smtpauthenticate", "1");
  mail.Fields.Add("http://schemas.microsoft.com/cdo/configuration/sendusername", msg.From.User);
  mail.Fields.Add("http://schemas.microsoft.com/cdo/configuration/sendpassword", "xxxxxxx");
  System.Web.Mail.SmtpMail.SmtpServer = msg.From.Host;
  System.Web.Mail.SmtpMail.Send(mail);
}

上記のほかにも注意すべき点がありますので、以下に書いておきます。

  • SmtpClient はサーバーから 250-AUTH=LOGIN というレスポンスが帰ってきても、 サーバーが LOGIN 認証をサポートしていると認識しない。認証手続きに入らず、いきなり MAIL FROM: **** が始まる。
  • MailDefinition クラスの BodyFileName プロパティに指定するメール本文のテキストファイルは、 UTF-8 または Unicode(UTF-16) でないと日本語が文字化けする。 (メモ帳の[名前をつけて保存]で[文字コード]を UTF-8 または Unicode にして保存する。 Visual Web Developer でテキストファイルを作るのはダメ)
  • FFFTP を使用して上記のテキストファイルをアップする場合、 Unicode (UTF-16) のファイルを ASCII モード(*.txt ファイルのデフォルト設定)でアップすると、 改行コードが変換され文字化けしてしまう。