@dltj qui. Non posso aiutarti con Node/JavaScript, ma posso offrire un po’ di pseudo-codice sotto forma di Python che sto usando per realizzarlo:
""" AWS Lambda per ricevere messaggi da SES e pubblicarli su 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):
"""Registra gli attributi dell'oggetto context ricevuto dall'invocatore Lambda"""
LOGGER.info(
"Tempo rimanente (ms): %s. Stream di log: %s. Gruppo di log: %s. Limiti memoria (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):
""" Gestisce l'evento di consegna SES """
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(
"Elaborazione di un SES con mID %s (%s) da %s",
mailMessageId,
sesMessageId,
mailSender,
)
deliveryRecipients = mail["destination"]
for recipientEmailAddress in deliveryRecipients:
LOGGER.info("Destinatario della consegna: %s", recipientEmailAddress)
s3resource = boto3.resource("s3")
bucket = s3resource.Bucket(EMAIL_S3_BUCKET)
obj = bucket.Object(sesMessageId)
LOGGER.info("Recupero %s/%s", EMAIL_S3_BUCKET, sesMessageId)
post_data = {"email": obj.get()["Body"].read()}
LOGGER.info("Invio a %s", DISCOURSE_SITE)
r = requests.post(
DISCOURSE_URL, headers=DISCOURSE_API_HEADERS, data=post_data
)
if r.status_code == 200:
LOGGER.info("Post accettato da Discourse: %s", DISCOURSE_SITE)
obj.delete()
processed = True
else:
LOGGER.error(
"Post rifiutato da %s (%s): %s",
DISCOURSE_SITE,
r.status_code,
r.content,
)
return processed
Sto usando Serverless per gestire il deployment e la manutenzione della Lambda. Nel caso in cui tu voglia seguire un percorso simile, sentiti libero di iniziare con questo file 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