今日は Salesforce World Tour Tokyo ということで
久しぶりの Salesforce ネタです。
(内容はイベントとか最近の技術と全く関係ないです)
今回はメール送信について。
Apex では Messaging.sendEmail()
メソッドでメールを送信できますが、
存在しないメールアドレス等、正しくメールが送信されなかった場合にどう検知すればいいの?
と思って調べてみました。
Messaging.sendEmail() の結果は SendEmailResult クラス
なのです。
そして、この SendEmailResult
クラスには isSuccess()
というメソッドが用意されており、
このメソッドによってメール送信の成否を判定することができます。
Messaging.SingleEmailMessage msg = new Messaging.SingleEmailMessage(); msg.setTargetObjectId('***************'); // またはアドレス直接指定 // msg.setToAddresses(new List<String> {'foo@example.com'}); msg.setPlainTextBody('This is the body'); List<Messaging.SendEmailResult> results = Messaging.sendEmail(new List<Messaging.Email> {msg}); if (results[0].isSuccess()) { // メール送信に成功した時の処理 System.debug(LoggingLevel.INFO, 'Succeeded'); }
問題点
ただ、上記の方法には2つの問題があります。
- メールアドレスの形式が不正だった場合、
isSuccess()
の前にエラーになる isSuccess()
は「送信が成功した」という判定だけで、実際に相手に届いたかどうかはわからない
問題1: メールアドレスの形式が不正だった場合にエラーになる
先ほどのサンプルコードを次のように変更します。
Messaging.SingleEmailMessage msg = new Messaging.SingleEmailMessage(); // @のない不正なメールアドレス形式 msg.setToAddresses(new List<String> {'zaki-yama.com'}); msg.setPlainTextBody('This is the body'); List<Messaging.SendEmailResult> results = Messaging.sendEmail(new List<Messaging.Email> {msg}); if (results[0].isSuccess()) { System.debug(LoggingLevel.INFO, 'Succeeded'); }
これを、たとえば開発者コンソールで実行すると以下のエラーが発生します。
System.EmailException: SendEmail failed. First exception on row 0; first error: INVALID_EMAIL_ADDRESS, Invalid to address : zaki-yama.com: []
メールアドレスそのものの書式チェックに引っかかってしまうと、エラーで処理が中断してしまうんですね...
これを避けるためには Messaging.sendEmail()
メソッドの第2引数に false
を指定します。
List<Messaging.SendEmailResult> results = Messaging.sendEmail(new List<Messaging.Email> {msg}, false);
こうするとエラーは発生せず isSuccess()
の結果が false
になるだけで済みます。
サンプル
Messaging.SingleEmailMessage msg = new Messaging.SingleEmailMessage(); msg.setToAddresses(new List<String> {'zaki-yama.com'}); msg.setPlainTextBody('This is the body'); List<Messaging.SendEmailResult> results = Messaging.sendEmail(new List<Messaging.Email> {msg}, false); if (results[0].isSuccess()) { System.debug(LoggingLevel.INFO, 'Succeeded'); } else { System.debug(LoggingLevel.INFO, 'Failed'); }
実行結果
00:48:22:029 USER_DEBUG [10]|INFO|Failed
問題2: isSuccess()
は実際に相手に届いたかどうかの判定には使えない
isSuccess()
は Salesforce が正常にメールを送信したことを保証するもののようで
ありもしないメールアドレスを指定しても false
にはなりません。
これでも isSuccess() = true
Messaging.SingleEmailMessage msg = new Messaging.SingleEmailMessage(); msg.setToAddresses(new List<String> {'hoge@zaki-yama.com'}); // 実際には存在しない msg.setPlainTextBody('This is the body'); List<Messaging.SendEmailResult> results = Messaging.sendEmail(new List<Messaging.Email> {msg}, false); if (results[0].isSuccess()) { System.debug(LoggingLevel.INFO, 'Succeeded'); } else { System.debug(LoggingLevel.INFO, 'Failed'); }
これはどうにかならないものか。。。
と調べてみると、Salesforce には「不達管理 (Bounce Administration)」というメール設定がありました。
「不達管理」機能による送信エラー検知
ここにあります。
メール管理 > 送信
この設定を有効にした状態で、取引先責任者やリードの「メール」に存在しないメールアドレスが設定されたレコードにメールを送信した場合
レコードの「メール」項目に警告アイコンが表示 され 、
(「メールアドレスの横の...」にチェックした場合)送信者に送信エラーメールが通知 されます 。
(「エラーが発生したメールを...」にチェックした場合)
「不達管理」は Apex でメール送信した時も有効
これがこの機能のいいところ。
setTargetObjectId()
で存在しないメールアドレスの取引先責任者・リードを指定した場合setToAddresses()
に存在しないメールアドレスを渡した場合
いずれも送信エラーメールは差出人に送信されます。
補足
一度不達メールだと判定されてしまった取引先責任者・リードを setTargetObjectId()
で指定してメールを送信すると
INVALID_EMAIL_ADDRESS エラーが出ます。
ので、Messaging.sendEmail()
の第2引数は false
にしといた方が良さそうですね。
リファレンス
http://www.kokyakukanri.info/salesforce/blog/2011/01/salesforce-6.html
SFDC:Messaging.sendEmailによるメール送信処理の送信失敗パターンテスト方法 - tyoshikawa1106のブログ