【问题标题】:SES: Accessing email body inside lambda functionSES:在 lambda 函数中访问电子邮件正文
【发布时间】: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 处理?

如果您需要查看发送的样本,请告诉我。

【问题讨论】:

    标签: node.js amazon-web-services aws-lambda amazon-ses


    【解决方案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 中的任何创建事件。

    【讨论】:

      猜你喜欢
      • 2016-04-29
      • 2015-12-13
      • 2018-11-14
      • 1970-01-01
      • 2020-10-11
      • 2016-11-17
      • 2019-03-05
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多