【AWS】ses send_emailでメール転送マンの作り方(メールエンコード参考用）【Amazon SES】

# 事の発端

**メールをよォ〜〜〜** 
**"みんな"で受信してェんだよォ〜〜〜**
**"メールアプリでSMTP認証して返信"してェんだよ〜〜〜**

お好みのソリューション（GoogleWorkspacesとか）で
エイリアスを噛ますほうが100万倍楽なのは承知済み。
諸事情のおかげで作り込むことになりました。

# 結論
~~SES+WorkMailのほうが運用コスト低いッスわ~~
不特定多数のメールアドレスからSESで受信して、Lambda+SESで不特定多数にメール転送
**aws ses send_mail API**でイイ感じに転送することができるようになりました。

#概要

1. どこかの誰かが送ったメールをSESで受信する
1. SESは受信イベントをS3とLambdaに通知・保存する
1. LambdaはS3からメールファイルを拾って、SESで転送する

#材料
##メール送信系API

sesには次のAPIがあります。

* send_mail
* send_raw_mail


###それぞれの違い

添付の有無。おわり（多分）
send_raw_mailは添付をつけられる。

細かいところだとMIMEファイルを取り込んで「えいや！」で転送できるのはsend_raw_mailのほう。
おそらく無差別に受けないならこっちのほうがとっても安心感が強い。と思う。

####所感
ネットに落ちてる情報だとsend_raw_mailの使い方が多いかな〜。
ていうかマニュアルに載ってる実装方法なので、イマイチ参考にならず。[^1]
**send_mail**でイイ感じに使えるのは珍しい（自画自賛）と思います。

SESはイベントの通知先にSNSトピックを使用する必要があり、
実際にメールを転送するためには2箇所に配信が必須。
とまぁLambda関数とS3が必要なんですが、このあたりはクラメソさんの記事を以下略

#本調理

##まねこんぽちぽち
クラメソさんの記事を参考に以下略

##コード書き書き
こんな感じです
S3からファイル引っ張ってエンコ処理→SESのAPIでメール送信　のところだけ載せておきます。
その他のの処理はまぁ、イベント変数から持ってきてよしなにしてるだけなので割愛

```python:lambda_func
#! /
# coding: utf-8

import boto3
import json
import logging
import traceback
import sys
import email
import base64
import os
from boto3.session import Session
from botocore.exceptions import ClientError,ParamValidationError
from botocore.client import Config

s3_cli = boto3.client('s3')
ses_cli = boto3.client('ses')

#メッセージ作成。S3からメッセージ取得して整形する。
def create_message(source):
    msg_encoding = 'utf-8'
    #msg_encoding_iso = 'iso-2022-jp'
    message_id=source['Records'][0]['ses']['mail']['messageId']
    
    #メッセージIDをキーにS3オブジェクト(メール)取得
    message_source = s3_cli.get_object(
    Bucket = s3_bucket,
    Key    = s3_key + message_id
    )
    
    msg = email.message_from_bytes(message_source['Body'].read())
    
    #メッセージをパート処理して本文抜き出し
    if msg.is_multipart() == False:
        #シングルパート
        byt = bytearray(msg.get_payload(), msg_encoding, 'ignore')
    else:
        #マルチパート
        prt = msg.get_payload()[0]
        byt = prt.get_payload(decode=True)
    
    #bytes型をstr型にデコード
    body = byt.decode(encoding=msg_encoding)
    
    #文字列を人間の読める型式にデコード
    message_org = base64.b64decode(body.encode("ascii")).decode(msg_encoding)
    
    #メッセージ生成
    messages = '''\
メール転送するでよ
誰から誰あてとか、メッセージID入れてあると親切かもね
****元ネタは***************************
'''+message_org+'''
****ここまで***************************
    '''    
    return messages

#send_mail APIの実行
def send_mail(messages):
    ses_var = ses_cli.send_email(
    Source=forward_from,
    Destination={
        'ToAddresses': あてさき,
    },
    Message={
        'Subject': {
            'Data': 'お知らせ',
            'Charset': 'UTF-8'
        },
        'Body': {
            'Text': {
                'Data': str(messages),
                'Charset': 'UTF-8'
            }
        }
    },
        ReplyToAddresses=[from_addr]
    )
    return ses_var
```

#課題
現状の仕組みだとutf-8でエンコードされたテキストメール**のみ**に対応しています。
本格的に対応しようとした場合、
文字コードやメールフォーマットに合わせて条件分岐したり例外処理したりが必要です。
**ここがマジでわからん**

[email.charset](https://docs.python.org/ja/3/library/email.charset.html)を使えば文字コードやメール型式（html,text）がワカルらしい。
全然追いついていないです。

とかとか、そういう条件分岐作りまくりの予感がしたので

* 受信：SESとWorkMailで受信して転送させる
* 送信：SESでSMTP認証作成してユーザに認証させる

こう実装したほうがいいんじゃねーかなって思ったワケであります。[^2]

[^1]: メールのお作法（emlの取扱）に明るいのかemail moduleでガリガリに書いている方は何件かいましたが、私にはナンノコッチャカさっぱりだったので一旦見なかったことにしました。
[^2]: こっちはこっちで結構面倒くさいらしい。ていうかメールサーバ自前で持つくらいならよそのサーバホスティング屋さんにメール鯖だけ借りたらいいじゃんとか思っちゃダメ？ダメですか。そうですよね。