Sto pensando che il modo migliore per implementare il ricevitore di posta (dato che uso già AWS SES) sia utilizzare l’API tramite una funzione lambda per chiamare l’endpoint API /admin/email/handle_mail
Ci sono tutorial su come inviare posta a SES e passarla tramite S3 a una funzione lambda. Ci sono alcune funzioni nodejs pre-costruite per prendere quell’email e inoltrarla a un server di posta.
Ma piuttosto che fare ciò, sembra meglio chiamare direttamente l’API da una funzione lambda passando l’email. (Non gestisco il mio server di posta locale e comunque non voglio usare il polling).
Quindi potrei usare un piccolo aiuto, sia tramite documentazione più dettagliata (nessuna pagina di documentazione per quanto ne so) su come chiamare quell’endpoint e cosa inviare esattamente (è un endpoint REST? c’è un’alternativa websocket? formato di ciò che si deve inviare?) o qualche codice da condividere. Devo ancora eseguire questo container aggiuntivo? Configure direct-delivery incoming email for self-hosted sites with Mail-Receiver (quel post ha ora 6 anni)
@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:
Come si crea quella chiave API (crittografata)? Deve essere crittografata?
Devo selezionare “Abilita polling manuale” Push emails using the API for email replies. per attivare l’endpoint API o è attivo per impostazione predefinita?
C’è qualcosa a cui prestare particolare attenzione in termini di autorizzazioni AWS o regole SES?
La chiave non ha bisogno di essere crittografata. Il codice dell’infrastruttura per il nostro progetto si trova in uno spazio condiviso, quindi non volevo codificare la chiave sorgente.
Ho “il polling manuale abilitato” sul mio sito, anche se non ricordo specificamente cosa faccia.
Niente di insolito che io possa ricordare con le autorizzazioni AWS oltre all’invio e alla lettura/scrittura nel bucket temporaneo.
C’è un posto nell’interfaccia web dove si genera la chiave API? Non riesco a trovare nulla nelle impostazioni. Forse la imposti semplicemente a ciò che desideri come variabile d’ambiente quando compili? Comunque, non ho idea di come generare una chiave API.
Sì, l’ho visto ma non pensavo fosse giusto perché “granular” non aveva il permesso handle_email ed ero incerto se scegliere un utente o tutti gli utenti.
Quindi ho generato una chiave per l’utente “system” con permesso globale. È quello che hai fatto?
Beh, volevo usare la mia app “postman” per imparare/provarla ma senza documentazione non so cosa inviare in quale/i formato/i e come passare la chiave. Se avessi più familiarità con python potrei forse capirlo guardando il tuo codice.
So che questo è un progetto open source, quindi è comprensibile che non ci sia una vera documentazione sull’uso dell’API handle_mail, solo un po’ di aiuto da persone come te… grazie!
Non è non documentato perché è open source, è non documentato perché nessuno (o non molti) l’hanno chiesto.
Suggerimenti che vuoi inviare tramite POST l’email codificata in una cosa email_encoded. routes.rb mostra che è un POST e il percorso, che è https://discourse.example.com/admin/email/handle_mail. L’ho preso dal modello di esempio del ricevitore di posta (e ti consiglio di usarlo, perché se l’avessi fatto, avresti già finito) ma è anche in discourse/config/routes.rb at main · discourse/discourse · GitHub (che non è immediatamente chiaro cosa stia succedendo a meno che tu non capisca rals).
@dltj Sono riuscito a riscrivere il tuo codice in nodejs usando aws-sdk e moduli get. Grazie mille.
Ci sono stati diversi ostacoli lungo il percorso, da AWS (ses, IAM, S3, lambda), a pasticciare con serverless, a ottenere la chiamata API corretta, fino a ottenere le impostazioni di discourse corrette.
Quello che farò è scrivere un argomento dettagliato su esattamente cosa ho fatto per far funzionare questo, abbastanza dettagliato che qualcuno potrebbe abilitarlo senza dover fare alcun tipo di codifica o tirarsi i capelli. Il vero vantaggio di questo metodo è che utilizzando ses NON è necessario configurare un server di posta elettronica per il dominio. Questo ti lascia libero di configurare un server di posta totalmente indipendente per il tuo dominio.
Se sei interessato a come è stato fatto, controlla di nuovo, posterò un link qui quando sarà pronto (tra qualche giorno).
Aggiungendo a questo, @dltj rimuoveremo presto il parametro email dal percorso admin/email/handle_mail, è necessario inviare il corpo dell’email come stringa codificata in base64 in un parametro email_encoded a questo percorso.
encoding era uno dei problemi che non riuscivo a risolvere.
Non riuscivo a far funzionare l’email codificata.
@martin, secondo il tuo post, email_encoded è errato. Ho provato entrambi, email_encoded genera un errore, ma encoded_email dà ancora l’avviso.
body: 'warning: the email parameter is deprecated. all POST requests to this route should be sent with a base64 strict encoded encoded_email parameter instead. email has been received and is queued for processing',
Devo convertire la mia posta in arrivo in testo normale (cosa che sto facendo ora) e riconvertirla in base64 o è probabile che ciò che AWS Ses memorizza nel bucket sia già in base64? Se passo il corpo dell’email come lo ha salvato SES, non appare nel registro delle email ricevute. Il comando post non restituisce errori, solo l’avviso. Quindi, fondamentalmente, sono bloccato qui.
Si prega di ritardare la rimozione della chiave email finché non saremo in grado di farlo funzionare.
Ancora una volta, se invio testo normale con “emal”, lo stesso messaggio viene ricevuto ed elaborato.
Continui a dire “strict”, questo significa qualcosa? Nodejs/JS ha solo due varianti di base64: “base64” e “base64url”.
Perché l’API continua a dare l’avviso se uso encoded_email anche se ho un errore nella codifica.
Ho provato curl e non gli piace encoded_email ma andava bene con email_encoded… uffa, quindi l’avviso è errato!
Quindi, ancora una volta ho provato il mio codice ma con email_encoded ma questa volta ho usato un modulo di codifica base64 invece di quello integrato e funziona, meno male!
Questo è fantastico, grazie per aver condiviso.
Abbiamo utilizzato la versione deprecata pre-base64 per tre anni su Lambda e si è bloccata un mese fa.
Non possiamo usare SMTP :25 poiché siamo ospitati dietro un tunnel cloudflared e perché giocare con la porta 25 se Amazon fa un ottimo lavoro bloccando il rumore con SES?
Comunque, sono alla fine della mia sanità mentale.
Il codice funziona con Postman e python eseguito su un computer locale. Qualcosa sembra corrompersi quando viene inviato da AWS Lambda con codice identico.
Forbidden
UTF-8
Bene, ho risolto il mio problema -
anche se le query venivano passate, la ‘modalità di lotta ai bot’ NON va d’accordo con l’API di Discourse. Forse a causa della codifica base64?
Spero che questo risparmi a qualcuno 72 ore della sua vita:
Disattiva questo: