HOWTO:亚马逊电子邮件服务器?

时间:2016-10-30 21:49:29

标签: php email amazon-web-services amazon-ec2 amazon-ses

我正在尝试为我的域构建一个电子邮件服务器...我现在正在做的是通过SES接收电子邮件并将它们存储在S3存储桶中,然后当用户访问收件箱时它会获取新电子邮件并将它们存储在我的EC2实例数据库中。

虽然它有效但我对此解决方案并不完全满意,有没有人知道其他/更好的方法来处理这种接收存储访问问题?

提前致谢。

2 个答案:

答案 0 :(得分:0)

您可以尝试在EC2实例上安装postfix(http://www.postfix.org/)和dovecot(http://www.dovecot.org/)。

答案 1 :(得分:0)

我已经解决了这个问题,并在我提出的另一个问题上发布了答案{。{3}}。

但无论如何我都会在这里重新发布:

所以我所做的就是将收到的电子邮件存储在S3存储桶中,而不是通知我的api新邮件已经到达(发送文件名)。最后从S3读取,解析,存储和删除S3,在我的api中。

SES规则: here

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电子邮件解析器(链接SES rules)的电子邮件解析器,我自己进行了一些更改,如果需要,我会进行编辑以显示源。

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