Translate

2011年5月6日金曜日

InboundEmailHandler内で自動返信メールまで送信するサンプル

電子メールtoケースを使用した場合

電子メールを受信の旨を自動返信する機能が

あらかじめ用意されていた。



InboundEmailHandlerを使用した場合

自動返信についてもApexコードで記述しなくてはならない。



以下のコードはForce.com開発者コースの演習で

使用されたサンプルで、

電子メールを受信処理後に送る処理を

行っている。







// Apex Code 演習9-2 アウトバウンドメールサービス(1)
// 到着した電子メールの本文を解釈して応募者(Candidate)レコードとして格納する
// 演習9-1の処理に加え、自動応答メール返信処理を追加
global class CandidateEmailHandler implements Messaging.InboundEmailHandler {

// 電子メール到着時に呼び出されるメソッド
// 引数: email 受信した電子メールデータ
// envelope 受信した電子メールのエンベロープ
global Messaging.InboundEmailResult handleInboundEmail(
Messaging.InboundEmail email, Messaging.InboundEnvelope envelope) {

// 戻り値インスタンス生成
Messaging.InboundEmailResult result =
new Messaging.InboundEmailresult();

// デバッグメッセージ用文字列変数
String myErr;

try{
// メール本文を格納する文字列変数
String theBody;

// 属性別に切り出された文字列を格納するリスト
List<String> fieldList = new List<String>();

// 受信メールがテキスト形式

if (email.plainTextBody != null){
// デバッグメッセージ変数に書き込み
myErr = 'plainTextBody=' + email.plainTextBody;
// メール本文を格納
theBody = email.plainTextBody;

// 受信メールがテキスト形式ではない(HTML形式)
} else {
myErr = 'htmlBody=' + email.htmlBody;
theBody = email.htmlBody;
}

// 本文を属性別に分解する
// 開始文字列、終了文字列にはさまれた文字列を切り出す
theBody = theBody.substring(
theBody.indexOf('[STARTBODY]')+11,
theBody.indexOf('[ENDBODY]'));
// セパレータ":"で分解しリスト化
fieldList = theBody.split(':',0);

// 分解元文字列と分解後をデバッグメッセージに追加
myErr += '\ntheBody=' + theBody;
myErr += '\nfieldList=' + fieldList;

// 属性名、属性値のMap化
Map<String,String> fieldMap = new Map<String,String>();

// 分解リストループ
for(String field : fieldList){
// "="で分割すると2つになる場合
if (field.split('=',0).size() == 2){
// 最初の要素をキー
// 2番目の要素を値として格納
fieldMap.put(
field.split('=',0)[0],
field.split('=',0)[1]);
}
}


// 応募者レコード
Candidate__c candidate;
try{
// 重複チェックのためにLastNameと電子メール
// アドレスが同じレコードを抽出
// 今回のアプリの仕様上LastNameとEmailで一意
// となっているはずなので存在しても1件のみ
// の想定であるためListではない
candidate =
[select id,
first_name__c,
last_name__c,
phone__c,
email__c,
ownerid
from candidate__c
where last_name__c =
:fieldMap.get(
'lastname')
and email__c =
:email.fromAddress];
// 既に存在する場合は、ほかの属性値更新のため
// このcandidate値を継続使用する
// 存在しない場合もQueryExceptionを発生させる
} catch (QueryException qe){
// candidateが存在しない場合は重複なしなので
// 新規作成する
if (candidate == null){
candidate = new Candidate__c();
}
// 処理継続させたいので再スローしない
}

// FirstName値上書き
candidate.first_name__c =
fieldMap.containsKey('firstname') ?
// 日本語が混じることも考えられるので
// EncodingUtilクラスを使ってエンコード
// する
EncodingUtil.urlDecode(
fieldMap.get('firstname'),'UTF-8') :
// nullの場合更新対象にならない
null;

// LastName値上書き
candidate.last_name__c =
fieldMap.containsKey('lastname') ?
EncodingUtil.urlDecode(
fieldMap.get('lastname'),'UTF-8') :
null;

// Phone値上書き
candidate.phone__c =
fieldMap.containsKey('phone') ?
EncodingUtil.urlDecode(
fieldMap.get('phone'),'UTF-8') :
null;
// Email値上書き
// 電子メールオブジェクトからなのでEncode不要
candidate.email__c = email.fromAddress;

try{
// 新規追加の場合
// (IDがまだ割り当てられていない)
if (candidate.id == null) {
// DBへ1件新規追加
insert candidate;
} else {
// 指定行を1件更新
update candidate;
}

// DB例外発生時処理
} catch (DMLException e){

// Error_Logレコードに例外情報を格納する
Error_Log__c log = new Error_Log__c();
log.trace__c = e.getTypeName() + '\n' +
e.getCause() + '\n' + e.getMessage() +
'\n\nfieldMap=' + fieldMap +
'\n\nmyErr=' + myErr;
insert log;

// 戻り値の成功フラグを偽にして返却
result.success = false;
return result;
}

// Comment欄データが存在する場合
// 応募者レコードのメモとして追加
// 「メモ&添付ファイル」関連レコードに格納される
if (fieldMap.containsKey('comment')){
// Note(メモ)レコード生成
Note cNote = new Note();
cNote.body = EncodingUtil.urlDecode(
fieldMap.get('comment'),'UTF-8');
cNote.parentId = candidate.id;
// タイトル文字列を格納
cNote.title = 'CandidateEmail:' + System.now();
try{
// Noteレコード格納
insert cNote;
// DB例外発生時処理
} catch (DMLException e){
// Error_Logレコードに書き込み
Error_Log__c log = new Error_Log__c();
log.trace__c = e.getTypeName() + '\n' +
e.getCause() + '\n' +
e.getMessage() +
'\n\nfieldMap=' + fieldMap +
'\n\nmyErr=' + myErr;
insert log;

// 戻り値の成功フラグを偽にして返却
result.success = false;
return result;
}
}

// バイナリorテキスト添付ファイル群を格納するリストを
// 新規生成
List<Attachment> attachments = new List<Attachment>();
// バイナリ添付ファイル群が存在する場合
if (email.binaryAttachments != null){
// バイナリ添付ファイルデータループ
for (Messaging.InboundEmail.BinaryAttachment
emailAttachment:
email.binaryAttachments){

// 新規添付ファイル格納オブジェクト生成
Attachment attachment =
new Attachment();
// 親IDとして応募者レコードを指定
attachment.parentId = candidate.id;
// データとしてそのまま格納
attachment.body = emailAttachment.body;
// ファイル名を指定
attachment.name =
emailAttachment.fileName;
// リストへ追加
attachments.add(attachment);
}
}

// テキスト添付ファイル群が存在する場合
if (email.textAttachments != null){
// テキスト添付ファイルデータループ
for (Messaging.InboundEmail.TextAttachment
emailAttachment:email.textAttachments){
// 新規添付ファイル格納オブジェクト生成
Attachment attachment =
new Attachment();
// 親IDとして応募者レコードを指定
attachment.parentId = candidate.id;
// データとしてBLOB型化して格納
attachment.body =
blob.valueOf(
emailAttachment.body);
// ファイル名を指定
attachment.name =
emailAttachment.fileName;
// リストへ追加
attachments.add(attachment);
}
}

// 格納対象となる添付ファイルが存在する場合
if (attachments.size() > 0){
try{
// 添付ファイル新規追加
insert attachments;
} catch (DMLException e){
// Error_Logレコードに例外情報を格納
Error_Log__c log = new Error_Log__c();
log.trace__c = e.getTypeName() + '\n' +
e.getCause() + '\n' +
e.getMessage() +
'\n\nfieldMap=' + fieldMap +
'\n\nmyErr=' + myErr;
insert log;
// 戻り値の成功フラグを偽にして返却
result.success = false;
return result;
}
}

// ここまで演習9-1の回答と同じ

// 演習9-2では送信元アドレスへ受信確認メールを自動
// で返信する処理を追加している

// 送信メール本文作成
String htmlBody =
buildOutboundEmailBody(
candidate.first_name__c);

// このコメントブロックはPDF(Visualforceページ)を
// 使って受信確認させる場合のサンプル
// buildOutboundEmailBody()メソッド呼び出している上
// の行と差し替えて使用する
// 前提)電子メールテンプレート
// 「CandidateEmailResponseTemplate」が登録済み
//
// 電子メールテンプレートのPageReferenceオブジェクト
// を取得
// PageReference templatePage =
// Page.CandidateEmailResponseTemplate;
// IDを応募者IDに差し替え
// templatePage.getParameters().put(
// 'id',candidate.id);
// リダイレクトを真に変更
// templatePage.setRedirect(true);
// 返信メール本文をPageReferenceから作成する
// ※このコードはSummer'08だと動作しない
// String htmlBody =
// templatePage.getContent().toString();

// 送信用メールメッセージの新規作成
Messaging.SingleEmailMessage emailOut =
new Messaging.SingleEmailMessage();
// サブジェクトの設定
emailOut.setSubject('Thank You for Your Email');

// 送信先アドレスの設定(受信メールのFromを指定)
String [] toAddresses =
new String[] {email.fromAddress};
emailOut.setToAddresses(toAddresses);

// メール本文の設定(HTML形式)
emailOut.setHtmlBody(htmlBody);

try{
// メールの送信
Messaging.SendEmailResult[] mailResults =
Messaging.sendEmail(
new Messaging.SingleEmailMessage[] {
emailOut});

// 送信結果をError_Logレコードに書き込み
List<Error_Log__c> logs =
new List<Error_Log__c>();
for (Messaging.SendEmailResult mailResult:
mailResults){
// 送信失敗の場合
if (!mailResult.isSuccess()){
// 例外情報を取り出す
Error_Log__c log =
new Error_Log__c();
log.trace__c =
'Error sending email to ' +
'candidate ' + candidate.id +
', ' + candidate.last_name__c +
'\n' + mailResult;
logs.add(log);
}
}
// 送信失敗の場合ログへ書き込む
if (logs.size() > 0) insert logs;

// メール送信以外の例外処理
} catch (Exception e){
// Error_Logへ例外情報書き込み
Error_Log__c log = new Error_Log__c();
log.trace__c = e.getTypeName() + '\n' +
e.getCause() + '\n' + e.getMessage() +
'\n\nfieldMap=' + fieldMap +
'\n\nmyErr=' + myErr;
insert log;
// 結果オブジェクトを成功フラグを立て返却
// メール送信以外は成功したという仕様かな?
result.success = true;
return result;
}

// 上記try-catch句以外で発生した例外処理
} catch (Exception e){
// 例外情報をError_Logへ書き込む
Error_Log__c log = new Error_Log__c();
log.trace__c = e.getTypeName() + '\n' + e.getCause() +
'\n' + e.getMessage() + '\n\nmyErr=' + myErr;
insert log;

// 結果オブジェクトの成功フラグに偽値を代入
result.success = false;
// 結果オブジェクトのメッセージに例外情報を書き込む
result.message = e.getTypeName() + '\n' +
e.getCause() + '\n' + e.getMessage() +
'\n\nmyErr=' + myErr;
// 結果オブジェクトの返却
return result;
}

// 結果オブジェクトを返却
// 正常終了の場合ここまで処理される
return result;

} // handleInboundEmail():終わり

// 送信元へ送る電子メール本文を作成する
// 引数: candidateName 応募者名
// 戻り値: HTML形式のメール本文文字列
private String buildOutboundEmailBody(String candidateName){

// 本来は電子メールテンプレート定義を使った処理がベター
// だがバグが治るまでは以下のようなべたな処理で対処する
String body = '<html><body><center><h1>';
body += UserInfo.getOrganizationName() + '</h1></center><p>';
body += 'Dear ' + candidateName + ',</p><p>';
body += 'Thank you for your interest in Universal Containers' +
body += '. Your email has been received and a recruiter will' +
body += ' evaluate it for potential opportunities within the' +
body += ' organization.';
body += 'We will keep your information on file, including an' +
body += 'y resume submitted, for one year. During that time' +
body += ' our recruiters will regularly search our pool of r' +
body += 'esumes for potential matches ';
body += 'within our open positions. You may be contacted by' +
body += ' one of our recruiters during the next year. There' +
body += ' is no need to respond to this email.';
body += '</p><p>Once again, we thank you for your submission' +
body += ' and interest.</p>';
body += 'Best Regards,</p><p>Recruiting Dept., Universal Con' +
body += 'tainers</p></p></body></html>';
return body;
}
}





処理の仕方は単純に

Messaging.sendMail()の使い方

を覚えればいいのだけど、

コメントにある通りバグフィックスされていないと

電子メールテンプレートをApexコードから活用することが難しい。

0 件のコメント:

既存アプリケーションをK8s上でコンテナ化して動かす場合の設計注意事項メモ

既存アプリをK8sなどのコンテナにして動かすには、どこを注意すればいいか..ちょっと調べたときの注意事項をメモにした。   1. The Twelve Factors (日本語訳からの転記) コードベース   バージョン管理されている1つのコードベースと複数のデプロイ 依存関係 ...