1
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 3 years have passed since last update.

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

Posted at

事の発端

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

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

結論

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

#概要

  1. どこかの誰かが送ったメールをSESで受信する
  2. SESは受信イベントをS3とLambdaに通知・保存する
  3. 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でメール送信 のところだけ載せておきます。
その他のの処理はまぁ、イベント変数から持ってきてよしなにしてるだけなので割愛

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を使えば文字コードやメール型式(html,text)がワカルらしい。
全然追いついていないです。

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

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

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

  1. メールのお作法(emlの取扱)に明るいのかemail moduleでガリガリに書いている方は何件かいましたが、私にはナンノコッチャカさっぱりだったので一旦見なかったことにしました。

  2. こっちはこっちで結構面倒くさいらしい。ていうかメールサーバ自前で持つくらいならよそのサーバホスティング屋さんにメール鯖だけ借りたらいいじゃんとか思っちゃダメ?ダメですか。そうですよね。

1
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
1
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?