AWS SESとLambdaで個人ドメインメールをGmailに転送

> 英語版はMediumで作成しました：[Forwarding Personal Domain Emails to Gmail with AWS Lambda and CloudFormation](https://medium.com/@yjzhang.me/forwarding-personal-domain-emails-to-gmail-with-aws-lambda-and-cloudformation-4a7208af4eb8)。日本語に自信がないので、ほぼGoogle Translateで作成しています。

**サマリー**：個人DomainのEmailを無料で信頼性の高いソリューションを構築するために、AWS無料利用枠サービス（SES、Lambda、S3）を使用してMIMEメールをアーカイブし、Gmailに転送します。他のソリューション：

* AWSブログ：[受信メールを外部の宛先に転送する](https://aws.amazon.com/blogs/messaging-and-targeting/forward-incoming-email-to-an-external-destination/)
* Githubリポジトリ：[aws-lambda-ses-forwarder](https://github.com/arithmetric/aws-lambda-ses-forwarder)

## まずはお試しください！
必要なインフラストラクチャはすべて[Github gist](https://gist.github.com/willings/7f0310c971278cddada267616a39f091)で更新されています。インフラストラクチャ全体を1-clickでセットアップするには、次のスクリプト（Linux / MacOS）を実行します。

### 前提条件
* 有効なAWSアカウント（[無料利用可能](https://aws.amazon.com/free/)）
* AWS Simple Email Serviceで[個人ドメインを確認する](https://docs.aws.amazon.com/ses/latest/DeveloperGuide/verify-domain-procedure.html)
* AWS Simple Email Serviceで[宛先メールを確認する](https://docs.aws.amazon.com/ses/latest/DeveloperGuide/verify-email-addresses-procedure.html)
    （SESは、サンドボックスステージで確認済みの宛先のみを許可します）
* [AWS CLI](https://docs.aws.amazon.com/cli/latest/userguide/cli-chap-install.html)をインストールする

### 追加情報
```
# Only needed if aws credentials are not set in ~/.aws/config, ensures your IAM user has permission to deploy CloudFormation stack
export AWS_ACCESS_KEY_ID=...
export AWS_SECRET_ACCESS_KEY=...
export AWS_DEFAULT_REGION=... e.g. us-west-2
# Configure domain and destination email information
STACK_NAME="EmailProxyStack"
DOMAINS="mydomain1.com,mydomain2.com"
MAIL_RECIPIENT="proxy_destination_email@gmail.com"
```

### スタックを作成する
```
# Get the CloudFormation template file (containing lambda code)
curl https://gist.githubusercontent.com/willings/7f0310c971278cddada267616a39f091/raw/43ccabcbb5254375e47a006d7d5878a2afff6eaa/email-proxy-stack.yaml > email-proxy-stack.yaml
# Create CloudFormation stack and deploy
aws cloudformation deploy \
    --capabilities CAPABILITY_IAM \
    --template-file email-proxy-stack.yaml \
    --stack-name ${STACK_NAME} \
    --parameter-overrides Domains="${DOMAINS}" MailRecipient="${MAIL_RECIPIENT}"
```

### 作成後の手順
* 作成したメールルールフィルターをコンソールで[有効にする](https://docs.aws.amazon.com/ses/latest/DeveloperGuide/receiving-email-receipt-rule-set.html?icmpid=docs_ses_console)
* セットアップ全体をテストするためにテストメールを送信する
* Gmailフィルターを設定して、ドメインのメールを異なるラベル/バケットに分類します。

## 仕組み
![CloudFormationEmail.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/130271/19047209-9378-8b39-4512-7f8c99da82b3.png)

1. MX設定がSESレコードに更新された後、ドメインEメールはAWS SESに転送されます：`10 inbound-smtp.regionInboundUrl.amazonaws.com`。詳細については、[SESのドキュメント](https://docs.aws.amazon.com/ses/latest/DeveloperGuide/receiving-email-mx-record.html)を参照してください。
2. メールルールフィルターでは、MIMEメールメッセージ全体をS3バケットに入れて、後で使用するためのアクションを追加します。バケット内のファイル名はメールメッセージIDと同じです。
3. Eメールルールフィルターでは、S3に格納した後、別のアクションがSES通知によってLambda関数をトリガーし、ラムダ関数コードがS3バケットからEメールをフェッチし、メッセージを目的の形式に更新し、今後の検索のためにCloudWatchログに記録します。
4. Lambda関数はSES `send_raw_email` apiを呼び出して、変更された電子メールメッセージを転送します。
5. SESはSMTPプロトコルを実行して、電子メールを宛先に送信します。

## その他
### Pros
* 費用はかかりません（S3は1年間の試用後の費用は少しかかる場合があります）
* できるだけ多くのメールアカウントを定義してください！
* 信頼性が高く、EC2の自己ホスト型電子メールサーバーと比較してサーバーのダウンを心配する必要はありません

### Why another wheel？
上記の両方の参照は、次の意味で理想的ではありません。
* コードとしてのインフラストラクチャとして実装されていないため、手動で構成する必要があり、人為的なミスが発生する可能性がある
* AWSブログの例はGmailでネイティブに表示できない`.eml`ファイルとして転送します
* Githubコードはテキストベースの処理を使用します。コードは少し複雑です。 pythonの組み込みの`email`パッケージは、より優れたソリューションのようです

### 将来の改善点
* ここでも、非アクティブなルールセットをアクティブに移動する手動の手順が必要です。この手順は、cloudformationスタックにカスタマイズされたリソースラムダを追加することで自動化できます。
* 処理に失敗した場合は、SNSからSMSに通知して、生のメールをキャッチして表示できるようにすることができます。

## トラブルシューティング
1. **メールが宛先メールボックスに転送されません。どこからデバッグを開始できますか？**
2〜5に従ってください。

2. **SESが私のメールを処理していることをどのようにして知るのですか？**
ドメインのMXレコードが正しく設定されていることを確認してください。DNSレコードの更新に多少の遅延がある可能性があることに注意してください。一部のMX DNSルックアップツール（[https://mxtoolbox.com/](https://mxtoolbox.com)など）も確認に役立ちます。

3. **ドメインに送信されたメールが「アドレスに到達できません」で拒否されるのはなぜですか？**
アクティブな電子メールルールフィルターがないことが原因である可能性があります。[作成されたルールフィルターがアクティブか非アクティブかを確認してください](https://docs.aws.amazon.com/ses/latest/DeveloperGuide/receiving-email-receipt-rule-set.html)。

4. **ラムダがリクエストを処理していることをどのようにして知ることができますか？**
  1. S3バケットをチェックして、新しいファイルが存在するかどうかを確認します
  2. CloudWatchログをチェックして、ラムダに処理エラーがあるかどうかを確認します

5. **ラムダが正しくトリガーされても、プロキシされたメールが宛先メールボックスに送信されないのはなぜですか？**
宛先のメールアドレスがホワイトリストに登録されていないことが原因である可能性があります。SESはデフォルトで、未確認のドメインへの送信メールをブロックします。

6. **スタックで作成されたリソースを見つけるにはどうすればよいですか？**
コンソールでCloudFormationスタックを確認します。正しいリージョンに切り替える必要がある場合があることに注意してください。