Python Lambda zum Senden von auf s3 hochgeladenen Dateien als E-Mail-AnhängePython

Python-Programme
Anonymous
 Python Lambda zum Senden von auf s3 hochgeladenen Dateien als E-Mail-Anhänge

Post by Anonymous »

Wir haben ein Online-Formular, das Leuten die Möglichkeit gibt, mehrere Dateien hochzuladen. Das Formular wird von einem Dritten erstellt, daher habe ich keine Beteiligung an diesem. Wenn jemand Dateien mithilfe des Formulars hochlädt, werden die Dateien in einem neuen Ordner innerhalb eines S3-Buckets abgelegt. Ich möchte in der Lage sein, Folgendes zu tun:

Die durch das Hochladen des Formulars ausgelösten Dateien abrufen
Die Dateien an eine E-Mail anhängen
Die E-Mail an bestimmte Personen senden.

Ich habe ziemlich viel recherchiert, aber ich bin noch ein Neuling im Programmieren und versuche, Python zu verwenden, auf das ich mich als erste richtige Sprache konzentrieren möchte.

Der Code I Die bisherige Darstellung ist von anderen Beispielen übernommen, die ich gesehen und angepasst habe. Bisher wurden mir jedoch nur E-Mails mit den Dateien gesendet, wenn ich einzelne Dateien in das Stammverzeichnis des Buckets hochgeladen habe. Nicht mehrere Dateien in einem Ordner im Bucket. Dies scheint darauf zurückzuführen zu sein, dass / im Pfad der Dateien in Ordnern die sendrawemail-Funktionalität unterbricht.

Dieses Lambda ist so eingerichtet, dass es durch eine PUT-Benachrichtigung bei der Erstellung neuer Dateien im S3-Bucket ausgelöst wird.
UPDATE: Ich habe jetzt anderen Code verwendet und habe eine Lösung. Bitte sehen Sie sich dazu unten an.

Code: Select all

from email.mime.text import MIMEText
from email.mime.multipart import MIMEMultipart
from email.mime.application import MIMEApplication
import boto3

def lambda_handler(event, context):
file_obj = event["Records"][0]
bucket_name = str(file_obj['s3']['bucket']['name'])
key = str(file_obj['s3']['object']['key'])
msg = MIMEMultipart()
new_body = "test body"
text_part = MIMEText(new_body, _subtype="html")
msg.attach(text_part)

filename = str(event["Records"][0]['s3']['object']['key'])
msg["To"] = "[email protected]"
msg["From"] = "[email protected]"
s3_object = boto3.client('s3')
s3_object = s3_object.get_object(Bucket=str(bucket_name), Key=str(key))
body = s3_object['Body'].read()

part = MIMEApplication(body, filename)
part.add_header("Content-Disposition", 'attachment', filename=filename)
msg.attach(part)
ses_aws_client = boto3.client('ses', 'eu-west-1')
ses_aws_client.send_raw_email(RawMessage={"Data" : msg.as_bytes()})
Ich hatte gehofft, dass ich beim Hochladen eines Ordners oder mehrerer Dateien eine E-Mail mit allen Dateien als Anhänge erhalten würde (ich weiß, dass es eine Beschränkung auf 10 MB für Nachrichten gibt). Wenn jedoch mehrere Dateien vorhanden sind, scheint es, als würden mehrere E-Mails mit einer Datei pro E-Mail gesendet. Und wenn sich die Datei in einem Ordner befindet, also einen Schlüsselwert mit einem Schrägstrich enthält, zeigt send_raw_email den folgenden Fehler an:

Code: Select all

[ERROR] ClientError: An error occurred (InvalidParameterValue) when calling the SendRawEmail operation: Expected ';', got "/"
Ich nehme an, ich muss den Pfad irgendwie kodieren? Gibt es eine Möglichkeit, alle neu hochgeladenen Dateien in einer E-Mail zusammenzufassen?

Jede Hilfe wäre sehr willkommen.

Edit 1: Gemäß Jerils Antwort teile ich den vollständigen Protokolleintrag des Fehlers. Außerdem habe ich eine Zeile in meinem ursprünglichen Codeblock übersehen, daher werde ich diese ebenfalls aktualisieren.

Code: Select all

12:14:59
[ERROR] ClientError: An error occurred (InvalidParameterValue) when calling the SendRawEmail operation: Expected ';', got "/" Traceback (most recent call last):   File "/var/task/lambda_function.py", line 26, in lambda_handler     ses_aws_client.send_raw_email(RawMessage={"Data" : msg.as_bytes()})   File "/var/runtime/botocore/client.py", line 320, in _api_call     return self._make_api_call(opera
[ERROR] ClientError: An error occurred (InvalidParameterValue) when calling the SendRawEmail operation: Expected ';', got "/"
Traceback (most recent call last):
File "/var/task/lambda_function.py", line 26, in lambda_handler
ses_aws_client.send_raw_email(RawMessage={"Data" : msg.as_bytes()})
File "/var/runtime/botocore/client.py", line 320, in _api_call
return self._make_api_call(operation_name, kwargs)
File "/var/runtime/botocore/client.py", line 623, in _make_api_call
raise error_class(parsed_response, operation_name)
Update:
Ich habe es jetzt geschafft, die wesentlichen Funktionen davon zum Laufen zu bringen:

Code: Select all

import os.path
import boto3
import email
from botocore.exceptions import ClientError
from email.mime.multipart import MIMEMultipart
from email.mime.text import MIMEText
from email.mime.application import MIMEApplication

s3 = boto3.client("s3")

def lambda_handler(event, context):
# Replace [email protected] with your "From" address.
# This address must be verified with Amazon SES.
SENDER = "Test Test "

# Replace [email protected] with a "To" address. If your account
# is still in the sandbox, this address must be verified.
RECIPIENT = "Test Test "

# Specify a configuration set. If you do not want to use a configuration
# set, comment the following variable, and the
# ConfigurationSetName=CONFIGURATION_SET argument below.
# CONFIGURATION_SET = "ConfigSet"

AWS_REGION = "eu-west-1"
SUBJECT = "Test Send Mesage with Attachment"

# This is the start of the process to pull the files we need from the S3 bucket into the email.
# Get the records for the triggered event
FILEOBJ = event["Records"][0]
# Extract the bucket name from the records for the triggered event
BUCKET_NAME = str(FILEOBJ['s3']['bucket']['name'])
# Extract the object key (basicaly the file name/path - note that in S3 there are
# no folders, the path is part of the name) from the records for the triggered event
KEY = str(FILEOBJ['s3']['object']['key'])

# extract just the last portion of the file name from the file. This is what the file
# would have been called prior to being uploaded to the S3 bucket
FILE_NAME = os.path.basename(KEY)

# Using the file name, create a new file location for the lambda. This has to
# be in the tmp dir because that's the only place lambdas let you store up to
# 500mb of stuff, hence the '/tmp/'+ prefix
TMP_FILE_NAME = '/tmp/' +FILE_NAME

# Download the file/s from the event (extracted above) to the tmp location
s3.download_file(BUCKET_NAME, KEY, TMP_FILE_NAME)

# Make explicit that the attachment will have the tmp file path/name. You could just
# use the TMP_FILE_NAME in the statments below if you'd like.
ATTACHMENT = TMP_FILE_NAME

# The email body for recipients with non-HTML email clients.
BODY_TEXT = "Hello,\r\nPlease see the attached file related to recent submission."

# The HTML body of the email.
BODY_HTML = """\



Hello!
Please see the attached file related to recent submission.


"""

# The character encoding for the email.
CHARSET = "utf-8"

# Create a new SES resource and specify a region.
client = boto3.client('ses',region_name=AWS_REGION)

# Create a multipart/mixed parent container.
msg = MIMEMultipart('mixed')
# Add subject, from and to lines.
msg['Subject'] = SUBJECT
msg['From'] = SENDER
msg['To'] = RECIPIENT

# Create a multipart/alternative child container.
msg_body = MIMEMultipart('alternative')

# Encode the text and HTML content and set the character encoding.  This step is
# necessary if you're sending a message with characters outside the ASCII range.
textpart = MIMEText(BODY_TEXT.encode(CHARSET), 'plain', CHARSET)
htmlpart = MIMEText(BODY_HTML.encode(CHARSET), 'html', CHARSET)

# Add the text and HTML parts to the child container.
msg_body.attach(textpart)
msg_body.attach(htmlpart)

# Define the attachment part and encode it using MIMEApplication.
att = MIMEApplication(open(ATTACHMENT, 'rb').read())

# Add a header to tell the email client to treat this part as an attachment,
# and to give the attachment a name.
att.add_header('Content-Disposition','attachment',filename=os.path.basename(ATTACHMENT))

# Attach the multipart/alternative child container to the multipart/mixed
# parent container.
msg.attach(msg_body)

# Add the attachment to the parent container.
msg.attach(att)
print(msg)
try:
#Provide the contents of the email.
response = client.send_raw_email(
Source=SENDER,
Destinations=[
RECIPIENT
],
RawMessage={
'Data':msg.as_string(),
},
#        ConfigurationSetName=CONFIGURATION_SET
)
# Display an error if something goes wrong.
except ClientError as e:
print(e.response['Error']['Message'])
else:
print("Email sent! Message ID:"),
print(response['MessageId'])
Das einzige Problem ist jetzt, dass mir beim Hochladen mehrerer Dateien eine E-Mail für jede Datei gesendet wird. Gibt es eine Möglichkeit, sie alle in einer E-Mail zusammenzufassen?

Quick Reply

Change Text Case: 
   
  • Similar Topics
    Replies
    Views
    Last post