「なりすまし? ダメにきまってんでしょ!?」
そう却下できたらいいんですが、世の中色々な人や仕事がありますので、そうもいかなかった。
業務改善のためにいわゆる”なりすまし”のメールを、業者向けに送らないといけなかった。
不特定多数に送信するのはNGだが、自分たちのサーバやソリューション向けに送信するのは100歩ゆずっておkすることにした。
Play Frameworkのmail pluginを使っていました。以前このブログで記事書いたことがある。
MailerAPI mail = init(); mail.setFrom("名字 名前 様 <from@gmail.com>"); mail.setRecipient("to@gmail.com"); mail.setSubject("テストの件名ですよー"); mail.send(views.html.mail.contents.render().toString().trim());
こんな感じ。
しかし。。。
使っているメールサーバが外部のサービスのサーバだっため、登録されているメールアドレスのドメインアドレス以外はエラーするって仕様だったのだ! 隊長ピンチ!
じゃあどうしよ! しかしわたしは元(エセ)ネットワークエンジニアだったのでメールの仕様はこちらのサイトで勉強していたのね。
メーラーで確認できるtoとfromは基本書き換え可能なため、「headerいじればええんじゃね?」ってひらめいたのだ。
じゃあ実装変えます。
MailerAPI mail = init(); mail.setFrom("from@gmail.com"); mail.addHeader("from", "名字 名前 様 <from@gmail.com>"); // これを追加 mail.setRecipient("to@gmail.com"); mail.setSubject("テストの件名ですよー"); mail.send(views.html.mail.contents.render().toString().trim());
addHeader
っていうメソッドがあったので、そこでheaderを追加するようにした。
おkおk〜。っと思いきや。
あれあれあれあれ〜? めっちゃエラーがでてる。。。
ぐぐったらこちらの記事が。。。なるほど。マルチバイト悪だな。
じゃあこのコードをJavaで実装するようにしました。
MailerAPI mail = init(); mail.setFrom("from@gmail.com"); mail.addHeader("from", encodeFromString("名字 名前 様", "from@gmail.com>")); mail.setRecipient("to@gmail.com"); mail.setSubject("テストの件名ですよー"); mail.send(views.html.mail.contents.render().toString().trim()); // ... 省略 private static String encodeFromString(String fromString, String mailAddress) { String fromText = ""; try { String encodeFromText = new String(fromString.getBytes("ISO2022JP")); String baseEncodeFromText = new String(Base64.encodeBase64(encodeFromText.getBytes())); fromText = "=?iso-2022-jp?B?" + baseEncodeFromText + "?=" + " <" + mailAddress + ">"; } catch (Exception e) { Logger.trace(e.toString()); } return fromText; }
Base64
は↓のライブラリをimportした
やっていることは単純で
- ISO2022JPでエンコードして
- ↑をBase64でエンコードして
- エンコードした文字列の先頭に"=?iso-2022-jp?B?"と、末尾に"?="をつける
- ↑の文字列に"<メールアドレス>"の文字列を半角空白文字で結合する
これでよし。これでエラーが発生せず、安全(?)でなりすましできるようになりました。
と思いきや。。。。この↑のコードではうまくいかないことがわかりました\(^o^)/オワタ
どうやら、"duplicate from"にひっかかったみたいで、サーバに渡せてもメールサーバがエラーを送信者に返す事態に。
うぐぐぐ・・・!どないせーちゅーねん。
ということで、色々探した結果 Mail Pluginではできないことが発覚しました。タイトル変えます。
んじゃ、どうすればいいの? JavaMailを使いましょう。
import javax.mail.Message; import javax.mail.PasswordAuthentication; import javax.mail.Session; import javax.mail.Transport; import javax.mail.internet.InternetAddress; import javax.mail.internet.MimeMessage; public class Mail public static void main(String args[]) { try { String makeFromText = "テスト様"; String fromText = encodeFromString(makeFromText, "spoofing@gmail.com"); // なりすましのメール sendMail( "件名", fromText, "to@gmail.com", "mail body" ); } catch (Exception $e) { // ... } } private static void sendMail(String subject, String from, String to, String body) throws Exception { // 定数は任意で設定ください String contentType = "text/plain; charset=UTF-8"; Properties props = new Properties(); props.put("mail.transport.protocol", "smtp"); props.put("mail.smtp.auth", "true"); props.put("mail.smtp.starttls.enable", "true"); props.put("mail.smtp.host", HOST); props.put("mail.smtp.port", PORT); props.put("mail.smtp.from", MAIL_LOGIN_ID); // これがSMTP Authに使うfrom Session mailSession = Session.getInstance(props); mailSession.setDebug(true); MimeMessage message = new MimeMessage(mailSession); message.addFrom(InternetAddress.parse(from)); // mail spoofing message.setRecipients(Message.RecipientType.TO, to); message.setSubject(subject); message.setContent(body, contentType); message.setHeader("Content-Transfer-Encoding", "7bit"); // 最初文字化けしたけど、この行を追加したらいけた Transport transport = mailSession.getTransport(); try{ System.out.println("Sending ...."); transport.connect(HOST, PORT, FROM_MAILADDRESS, PASSWORD); transport.sendMessage(message,message.getRecipients(Message.RecipientType.TO)); System.out.println("Sending done ..."); } catch(Exception e) { System.err.println("Error Sending: "); e.printStackTrace(); } transport.close(); } }
コメントにも書いていますが、PASSWORD
などの定数は任意で設定ください。
ちなみにGmailの場合は、Session mailSession = Session.getInstance(props);
の箇所を下記に拡張する必要がある。
Session mailSession = Session.getInstance(props, new javax.mail.Authenticator() { protected PasswordAuthentication getPasswordAuthentication() { return new PasswordAuthentication(FROM_MAILADDRESS, PASSWORD); } } );
これでうまくいきましたー!やったーー!
ちなみに、最初↑のコードをどっからかパクってきて、動作させようとしましたが、いまいちピンと来ず、混乱していました。
頭を整理するためにも質問サイトで質問事項を書いて、何がわからないのかを質問してみました。
汚い英語だと思いますが、返事が返ってくる! 何故かコメントで。。。(どうアクションすれば良いのだ)。あとみんなやさしいいい。うれしい。
↑は、mail.smtp.from
がエンベロープの"MAIL FROM"と言っているのかな? というかメールセッションの中に"from"を設定するところがあるじゃん!
ってことで、コメントと逆の発想でmail.smtp.from
に、メールサーバにログインするときに使うMAIL FROM
のIDを記述。
んで、おそらくエンベロープの"from"はmessage.addFrom(InternetAddress.parse(from)); // mail spoofing
←ここでしょ。ってことで、ここに記述。
そしたらでキタ━━━━(゚∀゚)━━━━!!
コードはちゃんと読もう&あとでコメントに感謝して解決内容を投稿しておきます。