SES:在 lambda 函数中访问电子邮件正文
Posted
技术标签:
【中文标题】SES:在 lambda 函数中访问电子邮件正文【英文标题】:SES: Accessing email body inside lambda function 【发布时间】:2017-03-25 03:42:18 【问题描述】:我对 AWS 比较陌生,我正在尝试通过 Lambda 函数处理我的电子邮件。我已经在 node.js 中构建了这个:
'use strict';
exports.handler = (event, context, callback) =>
var http = require('http');
var data = JSON.stringify(event);
var options =
host: 'my.host',
port: '80',
path: '/my/path',
method: 'POST',
headers:
'Content-Type': 'application/json; charset=utf-8',
'Content-Length': data.length
;
var req = http.request(options, function(res)
var msg = '';
res.setEncoding('utf8');
res.on('data', function(chunk)
msg += chunk;
);
res.on('end', function()
console.log(JSON.parse(msg));
);
);
req.write(data);
req.end();
;
我已经使用端点进行了测试,它工作得很好,问题是我刚刚意识到消息的正文从未发送过。如何访问消息正文以发送并由我的 api 处理?
如果您需要查看发送的样本,请告诉我。
【问题讨论】:
【参考方案1】:所以我所做的是将收到的电子邮件存储在 S3 存储桶中,而不是通知我的 api 新电子邮件已到达(发送文件名)。最后在我的 api 中从 S3 读取、解析、存储和删除。
SES 规则:
Lambda 通知功能:
请注意,第一条规则创建的 S3 文件的名称与消息 ID 相同,因此为
'fileName': event.Records[0].ses.mail.messageId
。
'use strict';
exports.handler = (event, context, callback) =>
var http = require('http');
var data = JSON.stringify(
'fileName': event.Records[0].ses.mail.messageId,
);
var options =
host: 'my.host',
port: '80',
path: '/my/path',
method: 'POST',
headers:
'Content-Type': 'application/json; charset=utf-8',
'Content-Length': data.length
;
var req = http.request(options, function(res)
var msg = '';
res.setEncoding('utf8');
res.on('data', function(chunk)
msg += chunk;
);
res.on('end', function()
console.log(JSON.parse(msg));
context.succeed();
);
);
req.write(data);
req.end();
;
API 函数(PHP - Laravel):
请注意,我正在使用基于 Plancake 电子邮件解析器(链接 here)的电子邮件解析器,并进行了一些我自己的更改,如果需要,我将进行编辑以显示源代码。
public function process_incoming_email(Request $request)
$current_time = Carbon::now()->setTimezone('Brazil/East'); // ALL TIMEZONES: http://us.php.net/manual/en/timezones.others.php
try
if ($request->has('fileName')
$file_name = $request->input('fileName');
// GET CREDENTIALS AND AUTHENTICATE
$credentials = CredentialProvider::env();
$s3 = new S3Client([
'version' => 'latest',
'region' => 'my-region',
'credentials' => $credentials
]);
// FECTH S3 OBJECT
$object = $s3->GetObject(['Bucket' => 'my-bucket', 'Key' => $file_name]);
$body = $object['Body']->getContents();
// PARSE S3 OBJECT
$parser = new EmailParser($body);
$receivers = ['to' => $parser->getTo(), 'cc' => $parser->getCc()];
$from = $parser->getFrom();
$body_plain = $parser->getPlainBody();
$body_html = $parser->getHTMLBody();
$subject = $parser->getSubject();
$error_message;
// PROCESS EACH RECEIVER
foreach ($receivers as $type => $type_receivers)
foreach ($type_receivers as $receiver)
// PROCESS DOMAIN-MATCHING RECEIVERS
if(preg_match("/@(.*)/", $receiver['email'], $matches) && $matches[1] == self::HOST)
// INSERT NEW EMAIL
$inserted = DB::table('my-emails')->insert([
// ...
]);
// ADD ERROR LOG IF PARSER COULD NOT FIND EMAILS
if($email_count == 0)
DB::table('my-logs')->insert(
['sender' => $request->ip(), 'type' => 'error', 'content' => ($error_message = 'Could not parse received email or find a suitable user receiving email.') . ' File: ' . $file_name]
);
// DELETE OBJECT FROM S3 IF INSERTED
else if(count($emails) == $email_count)
$s3->deleteObject(['Bucket' => 'my-bucket', 'Key' => $file_name]);
// RETURN SUCCESSFUL JSON RESPONSE
return Response::json(['success' => true, 'receivedAt' => $current_time, 'message' => 'Email successfully received and processed.']);
// ADD ERROR LOG IF NOT INSERTED
else
DB::table('my-logs')->insert(
['sender' => $request->ip(), 'type' => 'error', 'content' => ($error_message = 'Inserted ' . count($emails) . ' out of ' . $email_count . ' parsed records.') . ' File: ' . $file_name]
);
else
// ERROR: NO fileName FIELD IN RESPONSE
DB::table('my-logs')->insert(
['sender' => $request->ip(), 'type' => 'error', 'content' => ($error_message = 'Incorrect request input format.') . ' Input: ' . json_encode($request->all())]
);
// ERROR TREATMENT
catch(Exception $ex)
DB::table('my-logs')->insert(
['sender' => $request->ip(), 'type' => 'error', 'content' => ($error_message = 'An exception occurred while processing an incoming email.') . ' Details: ' . $ex->getMessage()]
);
// RETURN FAILURE JSON RESPONSE
return Response::json(['success' => false, 'receivedAt' => $current_time, 'message' => $error_message]);
【讨论】:
感谢您的跟进。遇到同样的问题。我们必须跳过这么多循环才能获得消息体,这似乎有点愚蠢(更不用说效率低下)。这仍然是您今天使用的相同解决方案吗? @DaveJ 不幸的是:/ @MatheusSimon - 我正在尝试使用 laravel 5.4 运行与您自己非常相似的东西,我使用 SES 接受所有传入的电子邮件,它们当前存储在 S3 中,我最初的想法是解析它们在 Lambda 上使用 javascript 函数,然后将它们发送到 laravel 以存储在 DB 中并显示在应用程序中,我可以通过获取 SES 存储的 S3 对象使用您使用的电子邮件解析器完全避免 lambda 吗?感谢任何帮助,谢谢。 @Birdy 没有。我的 lambda 正在做的只是告诉我的 api 已收到一封新电子邮件。请注意,电子邮件的正文没有发送到我的 api,只有它的 id。这就是我发现的解决方法,可以完全按照您的意愿进行操作,因为 aws 与 api 对话的唯一方法(使用 Web 服务)是通过 lambda 函数。 ps.:我已经详细说明了这个解决方案,如果你愿意,我可以帮助你:gmail dot com 上的 mattzsimon @Birdy 摘要:不能使用没有 lambda 的 web 服务,不能用 lambda 发送正文,所以:收到电子邮件,存储在 s3 中,用 lambda 通知 api,通过 api 从 s3 获取正文,解析和存储, (可选:从 s3 中删除的电子邮件)。如果这个问题有帮助,请给它并竖起大拇指。谢谢【参考方案2】:我有一个与另一个非常相似的解决方案,但步骤更少。可以设置 lambda 触发器。因此,我创建了一个存储桶myemailbucket
,并将邮件从 SES 发送到该存储桶。然后我将我的 lambda 函数的触发器更改为存储桶 myemailbucket
中 s3 中的任何创建事件。
【讨论】:
以上是关于SES:在 lambda 函数中访问电子邮件正文的主要内容,如果未能解决你的问题,请参考以下文章