@dltj さん、こんにちは。Node/JavaScript についてはお手伝いできませんが、私がこれを行うために使用している Python の疑似コードを提供できます。
""" AWS Lambda to receive message from SES and post it to Discourse """
import json
import logging
import boto3
import requests
from base64 import b64decode
LOGGER = logging.getLogger(__name__)
LOGGER.setLevel(logging.INFO)
# pylint: disable=C0301
ENCRYPTED_DISCOURSE_KEY = "{cyper-text}"
DISCOURSE_KEY = boto3.client("kms").decrypt(
CiphertextBlob=b64decode(ENCRYPTED_DISCOURSE_KEY)
)["Plaintext"]
DISCOURSE_SITE = "discuss.folio.org"
EMAIL_S3_BUCKET = "openlibraryfoundation-discourse-mail"
DISCOURSE_URL = f"https://{DISCOURSE_SITE}/admin/email/handle_mail"
DISCOURSE_API_HEADERS = {
"Api-Key": DISCOURSE_KEY,
"Api-Username": "system",
}
def log_lambda_context(context):
"""Log the attributes of the context object received from the Lambda invoker
"""
LOGGER.info(
"Time remaining (ms): %s. Log stream: %s. Log group: %s. Mem. limits(MB): %s",
context.get_remaining_time_in_millis(),
context.log_stream_name,
context.log_group_name,
context.memory_limit_in_mb,
)
def lambda_handler(event, context):
""" Handle SES delivery event """
log_lambda_context(context)
LOGGER.info(json.dumps(event))
processed = False
for record in event["Records"]:
mail = record["ses"]["mail"]
mailMessageId = mail["commonHeaders"]["messageId"]
sesMessageId = mail["messageId"]
mailSender = mail["source"]
LOGGER.info(
"Processing an SES with mID %s (%s) from %s",
mailMessageId,
sesMessageId,
mailSender,
)
deliveryRecipients = mail["destination"]
for recipientEmailAddress in deliveryRecipients:
LOGGER.info("Delivery recipient: %s", recipientEmailAddress)
s3resource = boto3.resource("s3")
bucket = s3resource.Bucket(EMAIL_S3_BUCKET)
obj = bucket.Object(sesMessageId)
LOGGER.info("Getting %s/%s", EMAIL_S3_BUCKET, sesMessageId)
post_data = {"email": obj.get()["Body"].read()}
LOGGER.info("Posting to %s", DISCOURSE_SITE)
r = requests.post(
DISCOURSE_URL, headers=DISCOURSE_API_HEADERS, data=post_data
)
if r.status_code == 200:
LOGGER.info("Mail accepted by Discourse: %s", DISCOURSE_SITE)
obj.delete()
processed = True
else:
LOGGER.error(
"Mail rejected by %s (%s): %s",
DISCOURSE_SITE,
r.status_code,
r.content,
)
return processed
デプロイと保守には Serverless を使用しています。同様の方法を検討される場合は、この serverless.yml ファイルから始めることができます。
service: ses-post-to-discourse
frameworkVersion: "=1.36.1"
provider:
name: aws
runtime: python3.7
onError: arn:aws:sns:us-east-1:{AWS_ACCOUNT}:ses-discourse-DLQ
region: us-east-1
iamRoleStatements:
- Effect: 'Allow'
Action:
- 'ses:SendBounce'
Resource:
- '*'
- Effect: 'Allow'
Action:
- 's3:*'
Resource:
- 'arn:aws:s3:::openlibraryfoundation-discourse-mail/*'
- Effect: 'Allow'
Action:
- 'kms:decrypt'
Resource:
- 'arn:aws:kms:us-east-1:{AWS_ACCOUNT}:key/{UUID-of-key}'
package:
include:
# - something
exclude:
- node_modules/**
- .venv/**
- __pycache__
- secrets.yml
functions:
emailDispatcher:
handler: post_ses_delivery_lambda.lambda_handler
events:
- sns: ses-discourse-inbound
# CloudFormation resource templates
resources:
Resources:
EmailDispatcherLogGroup:
Type: AWS::Logs::LogGroup
Properties:
RetentionInDays: "30"
plugins:
- serverless-python-requirements
custom:
pythonRequirements:
pythonBin: .venv/bin/python
dockerizePip: false