メール機能を実装してみる

GAEで作成してみている「かんばんりすと」の内容をメールで自分の携帯に送ってみたくなった。どうしてWebアプリなのにわざわざこんなことがしたいのかというと、自分は携帯のパケット定額プランには入っていなくて(節約のため au の Eプラン)、リストをチェックするにもパケット料金が掛かって嫌だなぁと思い、テキストの軽いページを作って凌いでいたが、twitterにメールでアクセスできる「やぶみん」というサービスを使っていて「なんでもメールで送っちゃえば無料じゃん、これはいい!」、と思ったからである。

で、GoogleAppEngineのアプリ内からメールを送信する方法は既にいろんなところで書かれていたのでやってみた。特に新しい話題は無いので以下は完全に自分用のメモ。

仕様イメージ

  • テキストフォームとボタンを表示
  • テキストフォームにメールアドレスを入力し、ボタンを押すと指定アドレスに表示中のタスクの内容(とりあえず、Waiting と TodoHighだけ)を送信する
  • 画面は切り替えずにメッセージで成功か失敗か表示する(つまり Ajax を使用)
  • 一度入力したメールアドレスは Cookie に保持しておき、次回表示時にはデフォルトでテキストフォームに表示しておく

実装

  • jspの適当な位置に以下を記述。サブミットでsendMailAjax()メソッドにメアドを設定して呼ぶ。
<form method="post" onsubmit="sendMailAjax($('#mail_addr').get(0).value);return false;">
  <input id="sendmail_button" type="submit" value="SendMail" style="font-size:12px" />
  <input type="text" id="mail_addr" name="ttl" value="" size="40" style="font-weight:normal;padding:2px;background:#ffc"/></br>
</form>
function sendMailAjax(addr) {
    $('#info').html("Sending mail to " + addr + " ...");
    $.ajax({
        type: "POST",
        cache: false,
        url: "sendmail",
        data: "mail_addr=" + addr,
        success: function(response){
            $('#info').html(response);
        }
    });
}
  • Ajaxから飛んで来る sendmail に対応したコントローラ SendmailController を生成する
    • とりあえずベタっと書いてみた
    • try{} の中がメール送信のメイン部分。
    • 送信元アドレスはアプリの開発者のメアドでないといけなかったため、別途 kanban.list@gmail.com のアカウントを新規で取得し、このアプリの開発者に追加した。(GAEアプリ設定画面の[Administration]->[Permissions]から登録)
    • エラーがスローされなかった場合はメアドをクッキー登録している(setMailAddrToCookie)
    • タスク表示のページでメアドのクッキーの内容を次回表示するようにする。(コードは省略)
    • レスポンスは OK か NG かの文字列を Ajax のハンドラに投げる
    • 複数の送信先を指定したい場合は msg.addRecipient() を何度も呼べば良い
package slim3.controller.todo;

import org.slim3.controller.Controller;
import org.slim3.controller.Navigation;

import java.io.UnsupportedEncodingException;
import java.util.Properties;
import javax.mail.MessagingException;
import javax.mail.Message;
import javax.mail.Session;
import javax.mail.Transport;
import javax.mail.internet.InternetAddress;
import javax.mail.internet.MimeMessage;
import javax.servlet.http.Cookie;

import slim3.service.todo.TodoTaskService;

public class SendmailController extends Controller {
    TodoTaskService service = new TodoTaskService();

    @Override
    public Navigation run() throws Exception {
        String user = sessionScope("user");
        String mail_addr = requestScope("mail_addr");

        String title_text = user + " りすと";

        // DataStoreからメール送信したいテキストを取得
        String list_text = service.getSendMailText(user);

        //メールを送る
        try {
            Session session = Session.getDefaultInstance(new Properties(), null);
            MimeMessage msg = new MimeMessage(session);
            msg.setFrom(new InternetAddress("kanban.list@gmail.com", "かんばんりすと", "ISO-2022-JP"));
            msg.addRecipient(Message.RecipientType.TO, new InternetAddress(mail_addr)); //送信先のメールアドレス
            msg.setSubject(title_text, "ISO-2022-JP");
            msg.setText(list_text, "ISO-2022-JP");
            Transport.send(msg);
            setMailAddrToCookie(mail_addr);

            response.getWriter().write("<font color=blue>SendMail OK! to " + mail_addr + "</font>");

        } catch (UnsupportedEncodingException e) {
            response.getWriter().write("<font color=red>SendMail NG-EncordError! to " + mail_addr + "</font>");

        } catch (MessagingException e) {
            response.getWriter().write("<font color=red>SendMail NG-MessageingError! to " + mail_addr + "</font>");
        }
        
        return null;
    }
    
    protected void setMailAddrToCookie(String addr){
        int cookie_age_sec = 60*60*24*30*12; // 12 month
        Cookie cookie = new Cookie("mail_addr",addr);
        cookie.setMaxAge(cookie_age_sec);
        cookie.setPath("/");
        response.addCookie(cookie);    
    }   
}
  • やっぱりメールで受け取れると凄く便利。家とかでタスクに登録して、出がけにメール送信しておいて後で見られる。自分が実際に使っている用途としては、日用品で足りないものをリストに日々 Waiting に登録しておき、買い物に行く際にメールで送信しておいて出先で見ながら買い物するという感じ(だから Waiting だけわかればいい)。今までは直にアプリにアクセスしていたらパケット代もったいなかったんだよなぁ。まさに自分用の節約機能。