S2Mai v0.9.0 の使い方

S2Mai(Mail Access Interface)は、インタフェースにアスペクトでメール送信機能を適用します。

サーバ設定

まず、全体に共通の設定を「mailProperties.dicon」というファイルに書いて、ルートパッケージに置きます。

デフォルトでは内容は下記のようになってます。

<component name="host">
    "localhost"
</component>
<component name="port">
    25
</component>
<component name="username">
    null
</component>
<component name="password">
    null
</component>
<component name="from">
    null
</component>
<component name="replyTo">
    null
</component>
<component name="returnPath">
    null
</component>
<component name="messageId">
    null
</component>
<component name="templateEncoding">
    "UTF-8"
</component>
<component name="connectionTimeout">
    10000
</component>
<component name="readTimeout">
    10000
</component>
<component name="mailCharset">
    "ISO-2022-JP"
</component>

このdiconファイルはjarにも入ってますので、デフォルト設定で問題なければ作成する必要はありません。

設定項目
host
SMTPサーバのホスト
port
SMTPのポート番号
username
SMTPにログインする必要がある場合、そのユーザー名
password
同じく、そのパスワード
templateEncoding
テンプレートのエンコーディング
connectionTimeout
SMTPサーバとの接続タイムアウト
readTimeout
SMTPサーバへの送受信時のタイムアウト
mailCharset
メールのエンコードに使用する文字コード

他プロパティは今の所見てません・・(忘れてた)。

基本的な使い方

まずメールの内容を保持するPOJOを作ります。

public class TestData{
    private String name;
    (setter、getter省略)
}

Maiを作ります。

public interface TestMai {
    void sendMail(TestData data);
}

メソッド名はなんでもかまいません。用途別に複数メソッドを定義してもいいです。

diconファイルを書いて、Maiをコンポーネントとして登録します。

■maitest.dicon

<include path="s2mai.dicon"/>
<component class="com.example.interceptors.TestMai">
    <aspect>s2MaiInterceptor</aspect>
</component>

s2mai.diconをincludeし、タグで、s2MaiInterceptorを適用します。

s2mai.diconはjarの中にありますのでカスタマイズしない限りは何もしなくていいです。

メールの設定を保持するdiconファイルを、Maiと同じパッケージに作ります。diconファイル名は、

  • Maiインタフェース名.dicon
  • Maiインタフェース名_メソッド名.dicon

の2通り指定出来ます。インタフェース名のみだと、各メソッド共通で適用されます。あるメソッドだけに適用したい場合は、_メソッド名をつけて下さい。

■TestMai_sendMail.dicon

<component class="com.ozacc.mail.Mail">
    <initMethod name="addTo"><arg>"rokugen@example.com"</arg></initMethod>
</component>

上記は、Toに「rokugen@example.com」を追加しています。ozaccさんのozacc-mail-libraryのMailクラスに直接設定してますので、詳しくはhttp://spring-ext.sourceforge.jp/oml/apidocs/com/ozacc/mail/Mail.htmlを参照して下さい。

テンプレートを作ります。ファイル名は、Maiインタフェース名_メソッド名.ftlにして下さい。テンプレートの一番上の行に、「Subject: (最後に半角スペース一個)」と書くと、それ以降を件名としてセットします。

■TestMai_sendMail.ftl

Subject: テストメールです。
${data.name}さんこんにちは。

mailProperties.diconのtemplateEncodingでUTF-8を指定してますので、UTF-8で保存します。POJOのプロパティを埋め込む場合には、「${data.property名}」と書きます。

で、実行します。

S2Container container = S2ContainerFactory.create("maitest.dicon");
TestMai mai = (TestMai) container.getComponent(TestMai.class);
TestData dto = new TestData();
dto.setName("六");
mai.sendMail(dto);

するとこんなメールが。

From:null
To:rokugen@example.com
(他省略)
Subject:テストメールです。

六さんこんにちは。

いじょう、0.1.0の機能でした。

しかし、これだと、メールの送信先をdiconに書かなきゃいけなかったり、書くにはozacc-mail-libraryのAPIを踏まえなきゃいけなかったりで、もうちょっとなんとかしたいですね。そこで0.9.0ですよ、と

つづく。

Maiにアノテーションでメール設定をセット

diconでなくて、Maiに直接アノテーションでToとかFromとか設定出来ます。その場合は、Maiインタフェース名.diconとか作らなくていいです。

public interface TestMai {
    static final String FROM = "hoge@foo.com";
    static final String TO = "rokugen@example.com";
    
    void sendMail(TestData data);
}

これでMai全体にFromとかToとか反映されます。メソッド単位にしたい時は、「メソッド名_TO」とかにしましょう。

public interface TestMai {
    static final String FROM = "hoge@foo.com";
    static final String TO = "rokugen@example.com";
    static final String sendMail2_TO = "kei@example.com";
    
    void sendMail(TestData data);
    void sendMail2(TestData2 data);
    void sendMail3(TestData3 data);
}

この場合、sendMailとsendMail3の実行時にToには「rokugen@example.com」が設定されて、sendMail2の実行時には「kei@example.com」が反映されます。

ToやCcやBccなど、複数指定するものには、配列での指定も出来ます。

さて、メールアドレスには、アドレス本体と別に名前をセットしたいですね。「六」みたいな。

この場合には、JavaMailのInternetAddress使うのが一般的(なのか?)ですが、これは初期化する時に例外キャッチしなきゃいけないので(マイッタマイッタ)、アノテーションに使えないのです。そこでS2Maiでアドレスと名前を保持するクラスを提供しています。org.seasar.mai.mail.MailAddressといいます。そのまんまですが。

    static final MailAddress FROM = new MailAddress("hoge@foo.com","送信元名");
    static final MailAddress[] TO = 
	    new MailAddress[]{new MailAddress("rokugen@example.com","六"), new MailAddress("mai@example.com","まい")};

MailAddressのコンストラクタの引数は、第一がメールアドレス、第二が名前になります。第二は省略可能です。MailAddress自体では、メールアドレスのフォーマットなど、規定に外れていても特にエラーは起きませんが、最終的にInternetAddressへとセットされるので、そこで例外が発生しますのでご注意下さい。

定数アノテーションには下記があります。

  • SUBJECT
  • FROM
  • TO
  • CC
  • BCC
  • REPLY_TO
  • RETURN_PATH

ここで設定された値は、Maiインタフェース名_メソッド名.diconで設定されたものより優先されます。

さて、これだとアプリ側で動的にセットする事が出来ませんね。それではフォームからsubmitされたアドレスに返信したり出来ません。ので、POJOのプロパティにセットする方法もあります。

つづく。

POJOのプロパティでGO

ToとかCcとか、動的にセットしたいですね。そう云う時はPOJOにそのものずばりの名前のプロパティを作ってあげます。先ほどのPOJOにプロパティを追加しましょう。

public class TestData{
    private String name;
    private InternetAddress from;
    private List to;
    private MailAddress[] cc;
    private String[] bcc
    private String subject;
    
    (setter、getter省略)
}

そうすると、ここで設定された値が、diconファイルの記述内容、Maiに書いたアノテーションのどれよりも優先されて反映されます。ただし、Subjectはテンプレートに書いたのが最優先です。

設定可能なプロパティは下記です。

プロパティ名 メール設定 指定可能な型
subject 件名 String
from From String,InternetAddress,MailAddress
to To String,InternetAddress,MailAddressおよびそれぞれの配列もしくはList
cc Cc String,InternetAddress,MailAddressおよびそれぞれの配列もしくはList
bcc Bcc String,InternetAddress,MailAddressおよびそれぞれの配列もしくはList
replyTo Reply-To String,InternetAddress,MailAddress
returnPath Return-Path String,InternetAddress,MailAddress

指定可能な型以外の場合はエラーにはなりませんが、nullが設定されます。また、fromなどを配列もしくはListにした場合は、最後の要素が反映されます(たぶん)。

Listの場合、要素の型がString、InternetAddress、MailAddress混在でも大丈夫です。

他に添付ファイル用のプロパティもありますが、それは後述します。

また、サーバの設定をmailProperties.diconで設定しましたが、POJOからの設定も可能です。特定のメールのみホストを切り替えたい、などの要件がある場合にはこちらで。

プロパティ名 サーバ設定 指定可能な型
host SMTPサーバ String
port SMTPポート String,Integer,int
username SMTPユーザー名 String
password SMTPパスワード String

で、添付ファイルにも対応していますが、それはまた次回の講釈で(芥川隆之風)。

テンプレートについて

現在、FreeMarkerをテンプレートエンジンとして採用しています。テンプレートの書き方などは下記URLを参照下さい。

http://freemarker.org/docs/index.html

でも英語なので、取り敢えずループの回し方くらいは書いておこうかな。ご注文商品一覧とか色々と使う事も多いと思いますので。

public class TestData{
    private String[] details;
    (setter、getter省略)
}

なんて場合、テンプレートでループを回して各行表示する場合はこうです。

<#list data.details as dtl>
    ${dtl}
</#list>

foreachとかに近いですね。

TODOとして、s2mai.diconを編集する事でテンプレートエンジンをVelocityへ切り替える事を考えています。

添付ファイル

添付ファイルを扱うには、S2Maiで提供している、org.seasar.mai.mail.AttachedFileを使います。

コンストラクタとして、下記が用意されています。

  1. AttachedFile(File file)
  2. AttachedFile(File file, String fileName)
  3. AttachedFile(InputStream inputStream, String fileName)
  4. AttachedFile(URL url, String fileName)

それぞれ第二引数でファイル名を設定しますが、適切な拡張子が必要となります。Fileのみを指定した場合は、そのファイル名がセットされます。

動作を保証するために、一応それぞれの設定値のsetterは用意してません。getterはあります。

POJOに添付ファイルプロパティを追加しましょう。

public class TestData{
    private String name;
    private AttachedFile file;
    (setter、getter省略)
}

プロパティ名は何でも構いません。型がAttachedFileであれば添付ファイルと見なします。

また、複数指定の場合は配列もサポートしています。さらに、プロパティを複数構えても大丈夫です。

public class TestData{
    private String name;
    private AttachedFile file;
    private AttachedFile[] files;
    (setter、getter省略)
}

fileとfilesのそれぞれにセットされたファイルが添付されます。

また、型をListにした場合は、このままだと要素の型が不確定のため無視されますが、プロパティ名を「attachedFile」と云う名前にすれば、添付ファイルとして扱います。

public class TestData{
    private String name;
    private List attachedFile;
    (setter、getter省略)
}

勿論、この「attachedFile」と云うプロパティ名は、単体AttachedFileでも配列でも付けて構いません。

ただし、ジェネリクスを用いた場合はこの規約を守らなくてもOKです。要素の型が保証されますので、プロパティ名は自由に付けられます。

public class TestData{
    private String name;
    private List<AttachedFile> fileList;
    (setter、getter省略)
}

このジェネリクスのサポートを使いたい場合は、s2-tiger.jarをクラスパスに含める必要があります。また、s2-tigerEJBに依存しているため、EJB実装が必要となります。

geronimo-j2ee_1.4_spec-1.0.jarは、tomcatで使う場合、servletAPIが含まれているのでjarごと無視されるそうなので、geronimo-ejb_2.1_spec-1.0.jarを別途用意するのが吉なようです。

勿論動かすサーバがJ2EEにフルに対応していたら不要です。この件に関してはこちらを。

http://s2container.seasar.org/ja/setup.html

ややこしければ、プロパティ名を「attachedFile」としてしまえば、素のまんまで動きますので。typoしやすそうだけど(それがプロパティ名なんでもOK機能を付けた理由)。

さて、Tigerと云えばTigerアノテーションですが、S2MaiにもTigerアノテーションがあります。これまたつづく。

つか、わかりやすいですかー?

つづきはこちら
http://d.hatena.ne.jp/rokugen/20061205

やっぱりテストがなあ

これでだいぶん使えるようになったと思うんですが、ユニットテストがなんとか出来ればなあと、ちょっと思ってます。

開発中も結合テストでは、ローカルで小さいSMTPサーバ立ち上げてやってたんですが、いい加減面倒くさくなってきた。

ozaccさんの奴みたくexpectedなメール内容を用意して、上手い事突合出来るように出来るといいなー。

なーんもアイデアないんですけどね。