はじめに
昨年の記事では、Windowsフォームアプリを使って.NET Framework標準機能とSecure Mailを比較して日本語の扱いがどのように違うかを検証しました。
今回、日本語メールを送信するために必要不可欠なコンポーネント「Secure Mail」が、ASP.NET MVC 3アプリやWindows Azureアプリで使えるかどうかを確認してみたいと思います。なぜこのような検証を行うかというと、動作保証環境にASP.NET MVC 3アプリが動作するのに必要な.NET Framework 4.0や、Windows AzureのOSであるWindows Server 2008 英語版/Windows Server 2008 R2 英語版が含まれていないためです。
現状の動作保障環境
開発ツール
- Visual Studio .NET 2003 日本語版
- Visual Studio 2005/2008 日本語版
フレームワーク
- .NET Framework 1.1 SP1/2.0/3.0/3.5
OS
- Windows 2000/XP/Vista 日本語版
- Windows Server 2003/2008 日本語版
この記事では、メーカーの代わりに動作保証を行うことを目的とはしていません。しかし、Secure Mailは多く環境で利用されているコンポーネントですので、最新の環境で日本語メールを送信する場合などの参考になればと思い、検証を進めていきます。
ASP.NET MVC 3アプリに適用
ASP.NET MVC 3は、Webの世界でメジャーなMVCスタイルでの開発をASP.NETで行うためのフレームワークです(参考:『ASP.NET MVC3入門』)。ASP.NET MVC 3アプリの開発にはVisual Studio 2010が必要で、Visual Studio 2010もSecure Mail 2.0Jの動作保証環境ではありません。
プロジェクトの作成
Visual Studio 2010を起動し、新規プロジェクトの作成で[ASP.NET MVC 3 Webアプリケーション]を選択します。
最終的にインターネット上のホスティングサービスに配置して動作チェックをするため、テンプレートは[インターネットアプリケーション]を選択します。
Secure Mail 2.0Jを使う前準備
Visual StudioのプロジェクトでSecure Mail 2.0Jを使うには、Secure Mailのコンポーネントの参照設定が必要です。
- ソリューションエクスプローラでプロジェクトを右クリックして[参照の追加]メニューを選択
- Dart.PowerTCP.SecureMail.dllを参照に設定
- ソリューションエクスプローラでプロジェクトを右クリックして[追加]-[新しい項目]メニューを選択
- テキストファイルとして「licenses.licx」を追加
Dart.PowerTCP.SecureMail.Smtp, Dart.PowerTCP.SecureMail Dart.PowerTCP.SecureMail.MessageStream, Dart.PowerTCP.SecureMail
モデルの追加
今回のサンプルでは、/Home/Index/のView(Webページ)にメール送信用のページを作成します。このViewで使用するロジックは、ModelsフォルダにHomeModelsモデルを作成して記述するのがMVCスタイルです。そのため、Secure Mailを使用するコードはHomeModelsモデルの中に記述することになります。
Imports System.ComponentModel Imports System.ComponentModel.DataAnnotations Public Class SendMailModel <Required(ErrorMessage:="SMTPサーバは必須です。")> <Display(Name:="SMTPサーバ")> Public Property SmtpServer As String <Required(ErrorMessage:="ポート番号は必須です。")> <Display(Name:="ポート番号")> Public Property SmtpPort As Integer <Required(ErrorMessage:="UserIDは必須です。")> <Display(Name:="UserID")> Public Property UserID As String <Required(ErrorMessage:="パスワードは必須です。")> <DataType(DataType.Password)> <Display(Name:="パスワード")> Public Property Password As String <Required(ErrorMessage:="メールアドレスは必須です。")> <DataType(DataType.EmailAddress)> <Display(Name:="メールアドレス")> Public Property MailAddress As String <Required(ErrorMessage:="送信先メールアドレスは必須です。")> <DataType(DataType.EmailAddress)> <Display(Name:="送信先メールアドレス")> Public Property ToAddress As String <Required(ErrorMessage:="件名は必須です。")> <Display(Name:="件名")> Public Property Subject As String <Required(ErrorMessage:="本文は必須です。")> <DataType(DataType.MultilineText)> <Display(Name:="本文")> Public Property Body As String End Class Public Class SendMailService Public Function SendMail(smtpServer As String, smtpPort As Integer, userID As String, password As String, mailAddress As String, toAddress As String, subject As String, body As String, result As String) As Boolean Dim isOK As Boolean = False Try Using _smtp As New Dart.PowerTCP.SecureMail.Smtp _smtp.Username = userID _smtp.Password = password _smtp.Server = smtpServer _smtp.ServerPort = smtpPort Using _msg As New Dart.PowerTCP.SecureMail.MessageStream _msg.From = New Dart.PowerTCP.SecureMail.MailAddress(mailAddress) _msg.To.Add(New Dart.PowerTCP.SecureMail.MailAddress(toAddress)) _msg.Charset = "ISO-2022-JP" _msg.ContentType = "text/plain" _msg.Header.Add(HeaderLabelType.ContentTransferEncoding, "7bit") _msg.Subject = subject _msg.Text = body _smtp.Send(_msg) isOK = True End Using End Using Catch ex As Exception result = ex.Message End Try Return isOK End Function End Class
- SendMailModelクラス:SendMailModelクラスには、メール送信ページで使う項目をプロパティとして定義します。Required属性で未入力時のエラーメッセージを指定し、Display属性で項目名を定義します。この定義はView側で参照できます。
- SendMailServiceクラス:SendMailServiceクラスはメール送信用のクラスです。このクラスの中でSecure Mailを使用しています。SmtpオブジェクトにSMTPサーバーとの接続に必要な情報を設定し、MessageStreamオブジェクトにメールのヘッダ情報と本文を設定して、SmtpオブジェクトのSendメソッドでメール送信します。
Viewデザイン
ロジック部分が完成したら、コントローラへモデルに記述したロジックを呼び出すコードを記入します。Index関数が2つあるのは、パラメタなしが対応するViewを呼び出したときに実行される関数と、HttpPost属性がついたパラメタありが対応するViewからSubmitされたときに実行される関数の2種類を用意する必要があるためです。
Public Class HomeController Inherits System.Web.Mvc.Controller Public Property SendMailService As New SendMailService Function Index() As ActionResult ViewData("Message") = "ASP.NET MVC へようこそ" Return View() End Function <HttpPost()> _ Function Index(ByVal model As SendMailModel) As ActionResult If ModelState.IsValid Then Dim result As String = "" If SendMailService.SendMail(model.SmtpServer, model.SmtpPort, model.UserID, model.Password, model.MailAddress, model.ToAddress, model.Subject, model.Body, result) Then Return RedirectToAction("Thanks", "Home") Else ModelState.AddModelError("", result) End If End If Return View(model) End Function Function Thanks() As ActionResult Return View() End Function End Class
- Index関数では画面入力をパラメタとして引き取ります。パラメタの形式は、対応するモデルになります。
- ModelStateのIsValidプロパティがFalseならば「入力値に違反がある」ということなので、すぐにReturn View(model)に制御が移ります。
- SendMailService.SendMailメソッドがTrue(メール送信成功)であれば、/Home/Thanks/ページに遷移します。
ビューの作成
[Views]-[Home]フォルダにあるIndex.vbhtmlファイルを開いて、SendMailModelクラスで定義された項目をHTMLの中に埋め込んでいきます。
@ModelType CZ1106Mvc3.SendMailModel @Code ViewData("Title") = "ホーム ページ" End Code <h2>@ViewData("Message")</h2> @Using Html.BeginForm() @Html.ValidationSummary(True, "メール送信に失敗しました。エラーを修正し、再試行してください。") @<div> <fieldset> <legend>メール送信</legend> <div class="editor-label"> @Html.LabelFor(Function(m) m.SmtpServer) </div> <div class="editor-field"> @Html.TextBoxFor(Function(m) m.SmtpServer) @Html.ValidationMessageFor(Function(m) m.SmtpServer) </div> : (中略) : <p> <input type="submit" value="送信" /> </p> </fieldset> </div> End Using
今回のViewはビューエンジンに「ASPX」ではなく「Razor」を採用しているため、HTMLにかなり近い記法になっています。
Razorらしい記述の1つとして、HTMLヘルパーによるレンダリングがあります。@Html.LabelFor、@Html.TextBoxFor、@Html.ValidationMessageForはすべて「Function(m) m.SmtpServer」というラムダ式をパラメタとして指定していますが、この3つのレンダリング結果はそれぞれ異なります。
- @Html.LabelFor:LabelForはSmtpServerプロパティのDisplay属性の設定値を表示するHTMLヘルパーなのでレンダリング結果はDisplay属性に指定されている「SMTPサーバ」になります。
- @Html.TextBoxFor:TextBoxForはSmtpServerプロパティの値をINPUTタブとして表示入力するHTMLヘルパーになります。
- @Html.ValidationMessageFor:ValidationMessageForはSmtpServerプロパティのRequired属性などのValidation関連の設定値を該当するValidationが発生したときに表示するためのHTMLヘルパーになります。
開発環境での実行
Model-View-Controlのコードが書けたら、IDE上で実行してみましょう。
画面が表示されたら、必要な情報を入力して[送信]ボタンをクリックします。正しく送信できたら「Thanks」ページが表示されます。
実際にメールクライアントで受信して、日本語表示用の変換を行う前(受信したまま)の状態を表示してみます(例えば、Becky!であれば[表示]-[ソースの表示]にて表示できます)。
From: hatsune@wankuma.com To: hatsune@wankuma.com Content-Type: text/plain; charset="iso-2022-jp" Content-Transfer-Encoding: 7bit Subject: =?iso-2022-jp?B?GyRCRnxLXDhsJE43b0w+JHI9aE19JDkkaxsoQnRlc3QbJEJNUTdvTD4bKEI=?= Date: Wed, 15 Jun 2011 20:25:45 +0900 MIME-Version: 1.0 Message-Id: <20110615110101.A2C4DFA402B@mail.wankuma.com> X-UIDL: aLG"!lDM"!c\/!!B-l"! $BF|K\8lK\J8(B
昨年の記事のWindowsフォームアプリの時と同様に、「MIME形式でISO-2022-JPで7bitエンコードされたメール」として送信されていることが分かります。もちろん、普通の表示方式で表示すれば、タイトルも本文もきちんと表示されます。
実環境に配置するときの注意点
ホスティングサービスなどで提供される環境には、Secure Mailはインストールされていません。しかし、Secure Mailを参照設定した場合は、自動的に[ローカルコピー]プロパティが「True」となっているため、Webの発行を行って配置すれば実行に必要なSecure MailのDLLがコピーされます。
ホスティングサービスによってはVisual Studioからの直接発行には対応していないところもありますが、そのような場合でもファイルシステムなどに発行して、そこからFTP転送などをすればよいでしょう。
Windows Azureアプリに適用
ASP.NET MVC 3アプリからSecure Mailが使えるのであれば、ASP.NET MVC 3アプリをWindows Azure上で動かした場合もSecure Mailが使えるかもしれないと考えました。現在、Windows AzureとしてSMTPサーバ機能は提供されていないため、Windows Azureアプリからメールを送信する時は、外部のSMTPサーバに接続してメール送信を行います。
Windows AzureにももちろんSecure Mailはインストールされていませんが、ASP.NET MVC 3をホスティングサービスへ発行する場合と同様に、DLLのローカルコピープロパティを「True」にしておけば、Windows Azureアプリとして作成してWindows Azureに配置した場合もSecure Mailの動作に必要なDLLがコピーされます。
Windows Azureアプリを作成
Windows Azureアプリを作成するには次の手順を踏みます。
- Visual Studio 2010を管理者として実行
-
新規プロジェクトの作成から[Windows Azureプロジェクト]を選択
- ロールはどのロールも選択しない
- ソリューションエクスプローラでソリューション名を右クリックして[追加]-[既存のプロジェクト]メニューを使って、既存のASP.NET Webアプリのプロジェクトを追加
-
Windows Azureプロジェクト側で「ソリューションWebロールプロジェクト」の追加を実施
-
ASP.NET MVC 3の動作に必要なDLLは残念ながらまだWindows Azureにはインストールされていないため、Secure Mailと同様に必要なDLLの参照設定の[ローカルコピー]プロパティを「True」にしてします。どの参照設定の変更が必要かは『ASP.NET MVC 3をAzureで動かす』を参考にしてください。
この手順によりASP.NET MVC 3アプリとして稼働していたサンプルをWindows Azure上で動作させるためのWindows Azureアプリが完成します。
Windows Azureに配置
Windows AzureアプリのVisual Studioでの一通りの動作確認が完了したら、ソリューションエクスプローラのWindows Azureプロジェクトを右クリックして[配置]メニューを選択します。
必要な情報を入れて[OK]ボタンをクリックすればWindows Azureにプログラムの配置が行われます。
Windows Azure環境での動作確認
Windows Azure Portalに表示されているDNS nameのURLをクリックすればWindows Azure上で稼働するWebアプリに接続します。
ここで各種情報をいれて[送信]ボタンをクリックすれば文字化けなく受信できるメールが送信されます。
From: hatsune@wankuma.com To: hatsune@wankuma.com Content-Type: text/plain; charset="iso-2022-jp" Content-Transfer-Encoding: 7bit Subject: =?iso-2022-jp?B?GyRCJDMkbCRPGyhCdGVzdBskQiRHJDkhIxsoQg==?= Date: Tue, 14 Jun 2011 13:57:38 +00 MIME-Version: 1.0 Status: U X-UIDL: 1308059860.25181.mbox401-3 $B$3$l$O(Btest$B$NK\J8$G$9!#(B
おわりに
ASP.NET MVC 3アプリからWindows Azureアプリを作成してSecure Mailですんなりメールが送信できたのには理由があります。それは次の3行の存在です。
_msg.Charset = "ISO-2022-JP" _msg.ContentType = "text/plain" _msg.Header.Add(Dart.PowerTCP.SecureMail.HeaderLabelType.ContentTransferEncoding, "7bit")
Windows Azureは英語環境なので、明示的に日本語を指定しないと「Content-Type: text/plain; charset="iso-8859-1"」となってしまい、メール本文が文字化けを起こします。Windows Azureを使うときの鉄則である「省略値は日本語指定とは限らないので、明示的に日本語を指定できるときは指定する」はここでも当てはまっていると言えるでしょう。