none
Web アプリケーションからメールを送信する方法 RRS feed

  • 質問

  • 自分の利用しているプロバイダの SMTP サーバーに直接メールを送信することを
    考えていますが、

     

    (1) SmtpClient が SMTP サーバーの要求する認証コマンドを出力してくれない。

    (2) TcpClient は、Web サーバーのセキュリティ制限(trust level="Medium")
      に引っかかる。

     

    という問題で行き詰っています。

     

    ローカル環境でプロトコルアナライザー (Wireshark) を使って調べたところ、
    SmtpClient を使用した場合、TCP コネクションが確立された後、以下のコマン
    ド/レスポンスのやり取りがされておりました。(下記で C: はクライアント、
    S: はサーバーの意味です。それらはコマンド/レスポンスには含まれません)。

     

    C: EHLO xxxxxxxx
    S: 250-サーバーのドメイン名 Hello xxxxxxxx, pleased to meet you
       250-AUTH CRAM-MD5 LOGIN PLAIN
       ・・・・・
    C: AUTH login アカウント名の Base64
    S: 500 authentication failed

     

    推測ですが、AUTH login の後アカウント名を続けて送るところがマズイようで、
    それをサーバーが有効なコマンドと認識しないため、認証失敗に終わっているよ
    うです。

     

    以下のように、AUTH LOGIN コマンドの後、サーバーのレスポンスを受けて、その
    後アカウント名、パスワードを送れば認証に成功します(Outlook Express を使っ
    て調べました)。

     

    C: AUTH LOGIN
    S: 334 VXNlcm5hbWU6
    C: アカウント名の Base64
    S: 334 UGFzc3dvcmQ6
    C: パスワードの Base64
    S: 235 Authentication successful

     

    そこで、TcpClient, StreamWriter, StreamReader を使用して、上記のような形
    で認証させることを考えましたが、自分の使っているレンタルの共用 Web サー
    バーではセキュリティの問題があることが分かって(trust level="Medium" で
    は TcpClient.Connect メソッドでセキュリティ例外が出る)、そこで行き詰っ
    ています。

     

    SmtpClient(これは trust level="Medium" でも OK なようです) を使って上
    記のようなコマンドを送る方法など、何か解決策がありましたら教えていただけ
    ると幸いです。

    2008年1月31日 9:35

回答

  • 表題の「Web アプリケーションからメールを送信する方法」については、一応目的を達成で

    きたので、このスレッドはクローズしたいと思います。

     

    その前に、自分の考える結論および最終的にどのようにメールを送信したのか書いておき

    たいと思います。

     

    あくまで自分が調べた限りで、自分の使用する SMTP サーバー/Web サーバーに限っ

    た話ですが、結論は以下のとおりと考えております。

     

    (1) SmtpClient がサポートしている SMTP 認証は LOGIN のみ。
    (2) LOGIN 認証の方法は標準化されていないので、今回の例のようにうまくいかない場

      合がある。
    (3) SmtpClient では、自分が使用する SMTP サーバーとの SMTP 認証の問題を解決

      する手段はない(少なくとも自分には見つからない)。
    (4) TcpClient は、自分が使用する Web サーバーのセキュリティ制限(trust level="Medium"

      相当)により使用不可。
    (5) 従って、System.Web.Mail.SmtpMail を使う以外に方法はなさそう。


    もともとの目的は以下の通りでした。

     

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

     

    System.Web.Mail.SmtpMail を使えば SMTP 認証ができないという問題は解決でき

    ます。

     

    次の問題は、CreateUserWizard, PasswordRecovery のメール送信機能を、どのように

    System.Web.Mail.SmtpMail を使用したコードに置き換えるかということでした。それに

    ついては、SendingMail イベントを処置するハンドラを作って、そこで CreateUserWizard,

    PasswordRecovery によるメール送信をキャンセルし、System.Web.Mail.SmtpMail を

    使用してメールを送信するようにしました。具体的には以下のような感じです。

    (以下で xxxxxxx はパスワード)

     

    Code Snippet

    protected void CreateUserWizard1_SendingMail(object sender, MailMessageEventArgs e)
    {
      e.Cancel = true;
      System.Net.Mail.MailMessage msg = e.Message;
      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);
    }

     

     


    その他、trapemiya さんのレス、

     

    > Becky! の場合には、数字複数桁.数字複数桁@サーバー名が Base64 でエンコー
    > ドされたものが、ユーザー名、パスワードの Base64 でエンコードされたものの
    > 代わりに出ています。

     

    が気になったので調べてみました。Bekcy の場合、SMTP 認証は CRAM-MD5, LOGIN,
    PLAIN をサポートしているそうで、「数字複数桁.数字複数桁@サーバー名」という
    のは、CRAM-MD5 方式での SMTP サーバーのレスポンスの一つのようです。

    2008年2月18日 2:07

すべての返信

  • 参考にならないかも知れませんが。

     

     SurferOnWww さんからの引用

    (1) SmtpClient が SMTP サーバーの要求する認証コマンドを出力してくれない。

     

    サードパーティ製のコンポーネント使って解決しました。

    # 業務システムの構築だったので、TcpClientなどを使って1から作成する手間とリスクは回避

     

    ただし、↓が解決できるかは不明です。

     SurferOnWww さんからの引用

    (2) TcpClient は、Web サーバーのセキュリティ制限(trust level="Medium")に引っかかる。

    2008年1月31日 10:58
  • 回答いただき有難うございました。

     

    ただ、自分の場合は、趣味のサンデープログラマーが自分のホームページに実装するコードを

    書いているというレベルですので、サードパーティ製のライブラリを使うのは選択肢に入ってい

    ないです。.NET Framework のクラスライブラリだけで何とかならないかと思っております。

    2008年2月1日 0:21
  •  SurferOnWww さんからの引用

    .NET Framework のクラスライブラリだけで何とかならないかと思っております。

     

    現在のコードは

    http://dobon.net/vb/dotnet/internet/smtpauth.html

    のような感じなのでしょうか。

     

    2008年2月1日 7:07
  • 返答を有難うございます。

     

    細かい点で違いますが、基本的にはその Web のページの1番目の例の通り、即ち
    認証関係のコードは以下のとおりです。

     

    SmtpClient smtpClient = new SmtpClient();
    smtpClient.Credentials = new System.Net.NetworkCredential(account, password);

     

    その他、以下のようなコードも試して見ましたが、コマンドが AUTH login xxxxxx
    となることには変わりなく、認証に失敗します。

     

    System.Net.NetworkCredential myCredential = new System.Net.NetworkCredential();
    myCredential.Domain = host;
    myCredential.UserName = account;
    myCredential.Password = password;
    SmtpClient smtpClient = new SmtpClient();
    smtpClient.Credentials = myCredential;

     

    なお、xxxxxx の部分が、1番目のコードでは account の Base64、2番目のコード
    では  host\account の Base64 と異なります。いずれにしてもサーバーは有効
    なコマンドと認識しないようで、500 authentication failed に終わりますが。

    2008年2月1日 9:41
  • 確認ですが、Outlook Expressで試されたとき、ESMTPで接続しに行っていましたでしょうか?

    2008年2月2日 6:42
    モデレータ
  • クライアントからの最初のコマンドが EHLO で始まり、それに対しサーバーからは 250 が

    帰ってきて、その後上記で書いたように AUTH LOGIN で認証に成功しています。

     

    ということで、ESMTP で接続しにいって、接続に成功したのは間違いないと思います。

    2008年2月3日 3:54
  • 了解しました。なんとなく環境の問題のような気がしたものですから。そうだ、あとはOP25Bなんかも大丈夫でしょうか?

     

    #メールサーバーまで届いているんで大丈夫のような気もしますが・・・

    2008年2月3日 5:33
    モデレータ
  • OP25B は問題ありません。そもそも、OP25B で引っかかっているとすると、EHLO とい

    うコマンドも出ないじゃないですか。telnet コマンドで SMTP サーバーのポート 25 に接続

    できるのも確認済みです。

     

    というより、OP25B などの環境による制限は、この問題とはまったく関係ないのです。

     

    問題はSmtpClient を使用すると AUTH login xxxxxx というコマンドになって即認証失敗

    になってしまうことです。

     

    それを、先に書きましたように、AUTH LOGIN → 334 VXNlcm5hbWU6 → アカウント名

    → 334 UGFzc3dvcmQ6 → パスワード、と順を追ったプロセスとする方法はないかを

    検討しています。

     

    2008年2月3日 7:06
  • 失礼しました。レンタルWebサーバー上からはOP25Bは大丈夫ということですね。Outlook Expressなどをローカル環境から試されているようでしたので、気になりました。

    ローカルからSmtpClientを試されてもダメだということですので、SmtpClient側の問題ということですね。

     

     SurferOnWww さんからの引用

    それを、先に書きましたように、AUTH LOGIN → 334 VXNlcm5hbWU6 → アカウント名

    → 334 UGFzc3dvcmQ6 → パスワード、と順を追ったプロセスとする方法はないかを

    検討しています。

     

    例えばBecky!ですとそのようなログが残りません。Outlook Expressではそのようなログが残ります。私はESMTPプロトコルについて詳しくないのですが、Becky!の場合には、数字複数桁.数字複数桁@サーバー名がBase64でエンコードされたものが、ユーザー名、パスワードのBase64でエンコードされたものの代わりに出ています。これは何でしょう? 無知でわかりません(^^;

    あまり関係ないかもしれませんが、参考までです。

     

    私はSmtpClientは直接使ったことがなく、Wankuma.Net.Mailを使わせていただいておりますが、特に問題なくsmtp認証で送信できていたと思います。(メールサーバーでローカルからはsmtp認証は要らないように設定したかな・・・? ごめんなさい。記憶が定かではありません)

    2008年2月3日 10:49
    モデレータ
  • 返答をありがとうございます。

     

    > レンタルWebサーバー上からはOP25Bは大丈夫ということですね。

     

    いえ、まだサーバーにアップするところまでいっていません。ローカル環境で
    試しています。ローカル環境でダメなものをサーバーにアップしても間違いな
    くダメですので、まずはローカル環境で問題ないことをチェックするのが先だ
    と思っております。

     

    サーバーでポート 25 をブロックしているかもしれませんが(問い合わせ中です。

    回答が来ないですが)、それはまた別の問題として対応予定です。

     

    > Becky!の場合には、数字複数桁.数字複数桁@サーバー名がBase64でエンコー
    > ドされたものが、ユーザー名、パスワードのBase64でエンコードされたもの
    > の代わりに出ています。

     

    Becky! は使ったことがないのでわかりませんが、必ずしも AUTH LOGIN →
    334 VXNlcm5hbWU6 → アカウント名 → 334 UGFzc3dvcmQ6 → パスワード、と
    言う手順でないとダメという事ではないようですね。

     

    SmtpClient で問題なく認証できたという話もあるようですので、サーバーに
    よっては AUTH login xxxxxx で認証できるようなサーバーもあるのかもしれ
    ませんね。

    2008年2月3日 11:50
  • 古い形式で、その使用は推奨されてないようですが、System.Web.Mail.SmtpMail を
    使ってみたところ、こちらは SMTP 認証が問題なくでき、メールは送信されました。

     

    Code Snippet

    System.Web.Mail.MailMessage mailMessage = new System.Web.Mail.MailMessage();
    mailMessage.To = "宛先メールアドレス";
    mailMessage.From = "送信者メールアドレス";
    mailMessage.Subject = "件名";
    mailMessage.Body = "本文";
    mailMessage.BodyEncoding = Encoding.UTF8;
    mailMessage.BodyFormat = System.Web.Mail.MailFormat.Text;
    mailMessage.Fields.Add("http://schemas.microsoft.com/cdo/configuration/smtpauthenticate", "1");
    mailMessage.Fields.Add("http://schemas.microsoft.com/cdo/configuration/sendusername", "ユーザー名");
    mailMessage.Fields.Add("http://schemas.microsoft.com/cdo/configuration/sendpassword", "パスワード");
    System.Web.Mail.SmtpMail.SmtpServer = "SMTP サーバーのドメイン名";
    System.Web.Mail.SmtpMail.Send(mailMessage);

     

     

     

    プロトコルアナライザーで見たコマンド/レスポンスのやり取りは以下のとおりでし
    た(C: はクライアント、S: は SMTP メールサーバーです)。

     

    C: EHLO クライアントのコンピューター名
    S: 250-サーバーのドメイン名 hello ...
       250-AUTH CRAM-MD5 LOGIN PLAIN
       ...その他のレスポンス...
    C: AUTH LOGIN
    S: 334 VXNlcm5hbWU6
    C: ユーザー名の Base 64
    S: 334 UGFzc3dvcmQ6
    C: パスワードの Base 64
    S: 334 UGFzc3dvcmQ6
    C: MAIL FROM: 送信者のメールアドレス
    S: 250 2.1.0 送信者のメールアドレス... Sender ok
    ...以下省略...

     

    さらに、Web サーバーにアップして試してみましたが、問題なく送信できました。

     

    非推奨とのことなので、あまり使いたくはないのですが、取りあえずの間はこれを
    使ってみようと思っています。

     

    SmtpMail を使わないでできる方法がありましたら、教えていただけると幸いです。

    2008年2月5日 13:34
  • 表題の「Web アプリケーションからメールを送信する方法」については、一応目的を達成で

    きたので、このスレッドはクローズしたいと思います。

     

    その前に、自分の考える結論および最終的にどのようにメールを送信したのか書いておき

    たいと思います。

     

    あくまで自分が調べた限りで、自分の使用する SMTP サーバー/Web サーバーに限っ

    た話ですが、結論は以下のとおりと考えております。

     

    (1) SmtpClient がサポートしている SMTP 認証は LOGIN のみ。
    (2) LOGIN 認証の方法は標準化されていないので、今回の例のようにうまくいかない場

      合がある。
    (3) SmtpClient では、自分が使用する SMTP サーバーとの SMTP 認証の問題を解決

      する手段はない(少なくとも自分には見つからない)。
    (4) TcpClient は、自分が使用する Web サーバーのセキュリティ制限(trust level="Medium"

      相当)により使用不可。
    (5) 従って、System.Web.Mail.SmtpMail を使う以外に方法はなさそう。


    もともとの目的は以下の通りでした。

     

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

     

    System.Web.Mail.SmtpMail を使えば SMTP 認証ができないという問題は解決でき

    ます。

     

    次の問題は、CreateUserWizard, PasswordRecovery のメール送信機能を、どのように

    System.Web.Mail.SmtpMail を使用したコードに置き換えるかということでした。それに

    ついては、SendingMail イベントを処置するハンドラを作って、そこで CreateUserWizard,

    PasswordRecovery によるメール送信をキャンセルし、System.Web.Mail.SmtpMail を

    使用してメールを送信するようにしました。具体的には以下のような感じです。

    (以下で xxxxxxx はパスワード)

     

    Code Snippet

    protected void CreateUserWizard1_SendingMail(object sender, MailMessageEventArgs e)
    {
      e.Cancel = true;
      System.Net.Mail.MailMessage msg = e.Message;
      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);
    }

     

     


    その他、trapemiya さんのレス、

     

    > Becky! の場合には、数字複数桁.数字複数桁@サーバー名が Base64 でエンコー
    > ドされたものが、ユーザー名、パスワードの Base64 でエンコードされたものの
    > 代わりに出ています。

     

    が気になったので調べてみました。Bekcy の場合、SMTP 認証は CRAM-MD5, LOGIN,
    PLAIN をサポートしているそうで、「数字複数桁.数字複数桁@サーバー名」という
    のは、CRAM-MD5 方式での SMTP サーバーのレスポンスの一つのようです。

    2008年2月18日 2:07
  •  SurferOnWww さんからの引用

    Bekcy の場合、SMTP 認証は CRAM-MD5, LOGIN,
    PLAIN をサポートしているそうで、「数字複数桁.数字複数桁@サーバー名」という
    のは、CRAM-MD5 方式での SMTP サーバーのレスポンスの一つのようです。

     

    なるほど。確かに、ログに

    250 AUTH LOGIN CRAM-MD5

    と出ていました。

    そこでSMTP認証をLOGINに変えてみたのですが、やはりユーザー名、パスワードは表示されませんでした。

    しかし、

    250 AUTH LOGIN CRAM-MD5
    AUTH LOGIN
    334 dXNlcm5hbWU6
    235 Authentication successful.

    と表示されるようになりました。

    dXNlcm5hbWU6は、username:ですので、ひょっとするとBecky!のログにはセキュリティのためにユーザー名とパスワードが表示されないのだろうか? と思ったり・・・。定かではありませんが。また、やっぱりCRAM-MD5が出ているのも気になりますが。

    2008年2月18日 4:58
    モデレータ
  • 今更ながらですが、Becky を使った場合のコマンド/レスポンスをプロトコルアナラ
    イザ (Wireshark) でキャプチャして調べてみました。結果は以下のとおりです。

     

    <CRAM-MD5 の場合>

     

    C: EHLO [IP アドレス]
    S: 250-AUTH CRAM-MD5 LOGIN PLAIN
       ・・・その他のレスポンス・・・
    C: AUTH CRAM-MD5
    S: 334 <24384.697.1204298562@ホスト>(の Base64 エンコード。334 は除く)
    C: ユーザーID e8c434aa28277966eeb31cb3789a810a(の Base64 エンコード)
    S: 235 Authentication successful
    ・・・以下省略・・・

     

    <LOGIN の場合>

     

    C: EHLO [IP アドレス]
    S: 250-AUTH CRAM-MD5 LOGIN PLAIN
       ・・・その他のレスポンス・・・
    C: AUTH LOGIN
    S: 334 VXNlcm5hbWU6
    C: ユーザーID(の Base64 エンコード)
    S: 334 UGFzc3dvcmQ6
    C: パスワード(の Base64 エンコード)
    S: 235 Authentication successful
    ・・・以下省略・・・

     

    というわけで、「Becky!のログ」とは異なる結果となりました。ご参考まで。

    2008年2月29日 15:58