SalesforceとAmazon SESを使ったメール配信システム

  • Posted on

はじめに

みなさんこんにちは。AWSも好きなSalesforceエンジニアの吉澤です。
今日はSalesforceとAmazon SESを使ったメール配信システムについてお話したいと思います。

メール送信におけるSalesforceの制限

1組織あたり1日に最大5000個の外部メールアドレスに対し一括メール送信ができる。
Salesforceの一括メール送信は取引先責任者、個人取引先、リード、および内部ユーザにのみ。
(内部ユーザへのメール送信は制限はありません。)
※Salesforceヘルプより引用

今回の仮想シナリオ

今回は、以下のような場合に、どうやったら簡単にメール配信ができるかを考えてみました。
1.Salesforceの外部ユーザ(5000人以上)に対し、ダイレクトメールを送付したい。
2.迷惑メール業者に認定されたくないので、不達管理は行う!

メール配信ができそうなツールを考えてみた。

メール配信を考えたときにまずはじめに思いついたのが、Amazon SESです。
Amazon SESはAmazon Web ServicesのEメールプラットフォームです。
メールの送信機能には以下のような特徴があります。
・SPFやDKIMなどの認証に対応している。
・メールが不達だった場合、Amazon SNSを使って結果を返してくれる。
・弊社連携ツールである、SkyOnDemandのメールアダプタを使うと簡単に送信できる。

こうした特長から、Amazon SES&SkyOnDemandであれば、今回の条件でも簡単にメール配信&不達管理ができそうです。

全体の構成

全体のシステム構成は以下のように設定しました。
システム構成図.png

1.配信者はメール対象オブジェクトに対象となるメールアドレスを登録します。
2.配信者がメール配信処理を行うと、SkyOnDemandがメール配信対象から対象メールアドレスを抽出し、Amazon SESを使ってメール配信される
3.不達のメールはAmazon SNSを使ってSalesforceに返され、Salesforceの処理で不達フラグを立てる。

メール送信設定

メール配信の事前準備として、メール送信サーバーのグローバルリソースの設定を行います。
こちらはリージョンごとに固定です。

メール送信設定.png

メール配信スクリプトはメールデータ取得→送信対象→宛先セット→メール送付と、これだけです。

スクリプト例.png

メール送信アイコンでは認証キーが必要ですので、以下のように設定します。
必須設定タブ
 送信元メールアドレス:AWS側で認証済のメールアドレス
認証タブ
 ユーザ名 :AWSで発行したメールユーザのアクセスキー
 パスワード:AWSで発行したメールユーザのシークレットキー

メール送信アイコン.png

メール送信はたったこれだけの作業でできました!

不達管理設定

不達になったメールはAmazon SNSで通知されます。
まずはAmazon SNSの仕様を調べてみました。

Amazon SNS

Amazon SNSの通知方法は6種類があります。
・HTTPS(JSON)
・HTTP(JSON)
・SQS
・Email
・Email-JSON
・Application
今回はSalesforceのメールサービスを使い、不達メールアドレスを受け取るようにしました。

メールサービス設定

メールサービス設定はこのような形で設定します

メールサービス.png

MailServiceClass

このメールサービスで呼び出すクラスでは、メール本文の解析、バウンスメールレコードを作成、メール本文内からステータス、メールアドレスを抽出し、メール配信対象オブジェクトを検索。該当するメールアドレスのメール配信対象に対し、不達のチェックフラグを立てる。
といった処理を行います。

global class BounceMailHandler implements Messaging.InboundEmailHandler {
global Messaging.InboundEmailResult handleInboundEmail(Messaging.InboundEmail email, Messaging.InboundEnvelope envelope) {
Messaging.InboundEmailResult result = new Messaging.InboundEmailresult();
try {
// バウンスメールを作成
Bouncemail__c bmail = new Bouncemail__c();
bmail.Detail__c = email.plainTextBody;
// ステータス検索
String statuscode = getObjectFromBody(bmail.Detail__c,'status\\\\":\\\\"','\\\\','"Message" : ','status');
bmail.Status__c = statusCode;
// メールアドレス検索
String bounceMailAdderess = getObjectFromBody(bmail.Detail__c,'destination\\\\":\\[\\\\"','\\\\','"Message" : ','destination');
bmail.Email__c = bounceMailAdderess;
// タイムスタンプ検索
Datetime bounceDatetime;
String bounceTimeStamp = getObjectFromBody(bmail.Detail__c,'Timestamp" : "','"','"Timestamp" : ','Timestamp');
if(!String.isEmpty(bounceTimeStamp)){
System.debug(bounceTimeStamp);
// 年取得
Integer bYear = Integer.valueOf(bounceTimeStamp.subString(0,4));
// 月取得
Integer bMonth = Integer.valueOf(bounceTimeStamp.subString(5,7));
// 日取得
Integer bDay = Integer.valueOf(bounceTimeStamp.subString(8,10));
// 時取得
Integer bHour = Integer.valueOf(bounceTimeStamp.subString(11,13));
// 分取得
Integer bMin = Integer.valueOf(bounceTimeStamp.subString(14,16));
// 秒取得
Integer bSec = Integer.valueOf(bounceTimeStamp.subString(17,19));
System.debug(bYear);
System.debug(bMonth);
System.debug(bDay);
System.debug(bHour);
System.debug(bMin);
System.debug(bSec);
// 日時型へ変換
Datetime tmpDate = datetime.newInstance(bYear,bMonth,bDay,bHour,bMin,bSec);
// 9時間加算
Datetime bDate =  tmpDate.addHours(9);
// 項目セット
bmail.SendDateTime__c = bDate;
}
if((statuscode=='5.1.1' || statuscode=='5.3.0') && !String.isEmpty(bounceMailAdderess)){
// 該当メールアドレスが設定されている取引先を検索
List<SendMailTo__C> bounceMailToList = getMailToFromEmail(bounceMailAdderess);
// メール配信対象更新
if(bounceMailToList != null && bounceMailToList.size() > 0){
for(SendMailTo__C cont : bounceMailToList){
cont.MailBounceFlg__c = true;
cont.MailBounceDate__c = SYstem.now();
}
update bounceMailToList;
// メール配信対象と紐づけ
bmail.mailToUpdateFlg__c = true;
}
}
Insert bmail;
}catch(Exception e){
String errMsg = '◆◆◆バウンスメール処理エラー:' + e.getMessage(); 
system.debug(errMsg);
// 本文のみセットし登録
Bouncemail__c errorMail = new Bouncemail__c();
errorMail.Detail__c = email.plainTextBody;
Insert errorMail;
// throw new EstimateWSMailHandlerException(errMsg);
}
return result;
}
}

※処理の基幹部分のみを抜粋

これで不達となった対象ユーザを把握できるようになりました。

まとめ


より充実した機能を求めるとApp Exchangeでメール配信サービスなどの利用を考えますが、今回は単純なメール配信サービスであれば、Salesforceと他のサービスをつなぐ事で比較的簡単にできました。
SalesforceやAWSはどんどんと新しいサービスが発表されておりますので、より新しいサービスを触ってみたいと思います。