SES: Accessing email body inside lambda function

无人久伴 提交于 2019-12-04 03:51:49

So what I did was storing the email received in an S3 bucket, than notifying my api that a new email has arrived (sending the file name). Finally read from S3, parsed, stored and deleted from S3, inside my api.

SES rules:

Lambda notifying function:

Note that the name of the S3 file created by the first rule is the same as the messages id, hence '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 function (PHP - Laravel):

Note that I'm using an email parser that's based on Plancake Email Parser (link here) with some changes of my own and if needed I'll edit to show the source.

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]);
}

I have a very similar solution to the other one, but with one fewer step. It is possible to set lambda triggers. So, I created a bucket myemailbucket, and sent the mail from SES to that bucket. Then I changed the trigger for my lambda function to any create event in s3 in the bucket myemailbucket.

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!