読者です 読者をやめる 読者になる 読者になる

ノラプログラマーの技術メモ

ネットで調べても出てこなかった情報を載せていきたい技術系ブログ。

androidアプリ開発でメールを自動送信させる方法

概要

androidアプリにメールを送らせる方法は2つある。ひとつはintentを使ってメーラーを起動させる方法。もうひとつはjava mailを使って自動送信させる方法だ。

既存のメーラーに処理を渡すやり方は簡単だけど、ユーザーに送信ボタンを押してもらう必要があり、またandroid端末に付属するメーラーによって挙動が違うことがある。

一方、java mailライブラリを使うやり方はプログラムが面倒臭い。だけどユーザーに手間を掛けさせることなく、アプリが自動的にメールを送信してくれる。今回は後者の方法を説明する。

開発環境

windows8.1
eclipse juno 4.2.1

手順

1.java mailライブラリをダウンロードする

下記のサイトから「activation.jar」「additionnal.jar」「mail.jar」をダウンロードする。

javamail-android - JavaMail port for the android plateform - Google Project Hosting

2.java mailライブラリをeclipseプロジェクトに配置する

eclipseのlibフォルダに「activation.jar」「additionnal.jar」「mail.jar」をドラッグ&ドロップして配置する。

f:id:kawai_norimitsu:20150104064108p:plain

コピーするかリンクするか聞かれるので、「copy files」を選択する。

f:id:kawai_norimitsu:20150104064155p:plain

3.マニフェストパーミッションを追加する

「AndroidManifest.xml」にインターネット通信権限を追加する。当然ながら、これがないとメール送信できない。

<uses-permission android:name="android.permission.INTERNET" />
4.androidアプリのプログラムを書く

まずはメールの送信部分。「修正」とコメントされている部分はご自分の環境に合うように変更してください。

public class MailSender {
    private Properties properties;
     
    public MailSender(){
        properties = System.getProperties();
    }
     
    public void send(){
        properties.put("mail.smtp.host", "smtp.host.com");		// ←修正
        properties.put("mail.smtp.port", "587");
        properties.put("mail.smtp.auth", "true");
        properties.put("mail.smtp.starttls.enable", "true");

        Session session = Session.getDefaultInstance(properties, new javax.mail.Authenticator(){
            protected PasswordAuthentication getPasswordAuthentication(){
                return new PasswordAuthentication("info@hoge.com", "hogehoge");		// ←修正
            }
        });
        MimeMessage message = new MimeMessage(session);
         
        try {
            String from = "info@hoge.com";		// ←修正
            String[] to = {"to@hoge.com"};		// ←修正
            message.setFrom(new InternetAddress(from));
            InternetAddress[] toAddress = new InternetAddress[to.length];
            for(int i = 0; i < to.length; i++ ){
                toAddress[i] = new InternetAddress(to[i]);
            }
            for(int i = 0; i < toAddress.length; i++){
                message.addRecipient(Message.RecipientType.TO, toAddress[i]);
            }

            message.setSubject("メールのタイトル");		// ←修正
            message.setText("メールの本文");		// ←修正
            Transport.send(message);
        } catch (AddressException e) {
            e.printStackTrace();
        } catch (MessagingException e) {
            e.printStackTrace();
        }
    }
}

これを呼び出すには下記のようなコードを書く。

MailSender ms = new MailSender();
ms.send();

・・・が、次のエラーが出た。

01-04 05:51:39.914: D/my app(32699): android.os.NetworkOnMainThreadException
01-04 05:42:24.504: W/System.err(26066): javax.mail.AuthenticationFailedException
01-04 05:42:24.504: W/System.err(26066): 	at javax.mail.Service.connect(Service.java:319)
01-04 05:42:24.504: W/System.err(26066): 	at javax.mail.Service.connect(Service.java:169)
01-04 05:42:24.504: W/System.err(26066): 	at javax.mail.Service.connect(Service.java:118)
01-04 05:42:24.504: W/System.err(26066): 	at javax.mail.Transport.send0(Transport.java:188)
01-04 05:42:24.504: W/System.err(26066): 	at javax.mail.Transport.send(Transport.java:118)
01-04 05:42:24.504: W/System.err(26066): 	at com.kawaidesu.mail.MainActivity$MailSender.send(MainActivity.java:138)
01-04 05:42:24.504: W/System.err(26066): 	at com.kawaidesu.mail.MainActivity$AsyncHttpRequest.doInBackground(MainActivity.java:86)
01-04 05:42:24.504: W/System.err(26066): 	at com.kawaidesu.mail.MainActivity$AsyncHttpRequest.doInBackground(MainActivity.java:1)
01-04 05:42:24.504: W/System.err(26066): 	at android.os.AsyncTask$2.call(AsyncTask.java:288)
01-04 05:42:24.504: W/System.err(26066): 	at java.util.concurrent.FutureTask.run(FutureTask.java:237)
01-04 05:42:24.504: W/System.err(26066): 	at android.os.AsyncTask$SerialExecutor$1.run(AsyncTask.java:231)
01-04 05:42:24.504: W/System.err(26066): 	at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1112)
01-04 05:42:24.504: W/System.err(26066): 	at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:587)
01-04 05:42:24.504: W/System.err(26066): 	at java.lang.Thread.run(Thread.java:841)

androidアプリでは、メインスレッドにネットワーク(HTTP)通信の処理を入れることは出来ないらしい。仕方ないので非同期スレッドを用意して、そのスレッド内でメール送信処理をする。

public class AsyncHttpRequest extends AsyncTask<Uri.Builder, Void, String> {
    @SuppressLint("UnlocalizedSms") @Override
    protected String doInBackground(Builder... params) {
    	try {
    		// ----- メール送信
    		MailSender ms = new MailSender();
    		ms.send();
        } catch (Exception e) {
            return e.toString();
        }
    	return null;
     }

    @Override
    protected void onPostExecute(String result) {
        Toast.makeText(getBaseContext(), "メールを送信しました", Toast.LENGTH_SHORT).show();
    }
}

最後に、ボタンクリックなどのイベント内で非同期スレッドを起動するプログラムを書く。

public void onClick(View v) {
    switch(v.getId()){
    case R.id.button1:
        // ----- 非同期通信
        Uri.Builder builder = new Uri.Builder();
        AsyncHttpRequest task = new AsyncHttpRequest();
        task.execute(builder);
    }  
}

以上ですー。

ソースコード見た方が早いよ!」という人のために、GitHubにサンプルプロジェクトをアップロードしておきました。そちらもどうぞ。