dackdive's blog

新米webエンジニアによる技術ブログ。JavaScript(React), Salesforce, Python など

[Salesforce]メール送信のエラー検知あれこれ (不達管理など)

今日は 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つの問題があります。

  1. メールアドレスの形式が不正だった場合、isSuccess()の前にエラーになる
  2. 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)」というメール設定がありました。

「不達管理」機能による送信エラー検知

ここにあります。

メール管理 > 送信

f:id:dackdive:20141202081147p:plain

この設定を有効にした状態で、取引先責任者やリードの「メール」に存在しないメールアドレスが設定されたレコードにメールを送信した場合

  • レコードの「メール」項目に警告アイコンが表示    され 、
    (「メールアドレスの横の...」にチェックした場合)

  • 送信者に送信エラーメールが通知           されます 。
    (「エラーが発生したメールを...」にチェックした場合)

f:id:dackdive:20141202081154p:plain

f:id:dackdive:20141204011246p:plain

「不達管理」は Apex でメール送信した時も有効

これがこの機能のいいところ。

  • setTargetObjectId() で存在しないメールアドレスの取引先責任者・リードを指定した場合
  • setToAddresses() に存在しないメールアドレスを渡した場合

いずれも送信エラーメールは差出人に送信されます。

補足

一度不達メールだと判定されてしまった取引先責任者・リードを setTargetObjectId() で指定してメールを送信すると
INVALID_EMAIL_ADDRESS エラーが出ます。

ので、Messaging.sendEmail() の第2引数は false にしといた方が良さそうですね。

リファレンス

Help And Training Community

Salesforce Developers

Salesforce Developers

http://www.kokyakukanri.info/salesforce/blog/2011/01/salesforce-6.html

SFDC:Messaging.sendEmailによるメール送信処理の送信失敗パターンテスト方法 - tyoshikawa1106のブログ