Python Lambda to send files uploaded to s3 as email attachments - python

We have an online form that gives people the option to upload multiple files. The form is built by a third party, so I don't have any involvement with them. When someone uploads files using the form it dumps the files into a new folder within an s3 bucket. I want to be able to do the following:
Get the files triggered by form filler's upload
Attach the files to an email
Send the email to specific people.
I have done quite a lot of research, but I'm still new to coding and am trying to use Python, which I have decided to focus on as my first proper language.
The code I have got so far is borrowed from other examples I have seen and adjusted. But so far it has only sent me emails with the files when I have uploaded single files into the root of the bucket. Not multiple files into a folder in the bucket. This appears to be because the / in the path of the files in folders breaks the sendrawemail functionality.
This lambda is set up to be triggered by a PUT notification on the creation of new files on the s3 bucket.
UPDATE: I have now used different code and have got a solution. Please see the bottom for this.
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"] = "test#test.com"
msg["From"] = "test#test.com"
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()})
What I hoped was that when a folder, or multiple files were uploaded, I would be sent an email containing all of the files as attachments (I realise there's a 10mb limit to messages). However, when there are multiple files it appears to be sending multiple emails with one file per email. And if the file is in a folder, so has a key value with a slash in it, the send_raw_email shows the following error:
[ERROR] ClientError: An error occurred (InvalidParameterValue) when calling the SendRawEmail operation: Expected ';', got "/"
I presume I need to encode the path in some way? Is there any way of collating all the files newly uploaded into one email?
Any help would be massively welcome.
Edit 1: As per Jeril's response, I'm sharing the full log entry from the failure. Also I missed a line in my original code block so I will update that, too.
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:
I have now managed to get the essential functionality of this working:
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 sender#example.com with your "From" address.
# This address must be verified with Amazon SES.
SENDER = "Test Test <test#test.com>"
# Replace recipient#example.com with a "To" address. If your account
# is still in the sandbox, this address must be verified.
RECIPIENT = "Test Test <test#test.com>"
# 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 = """\
<html>
<head></head>
<body>
<h1>Hello!</h1>
<p>Please see the attached file related to recent submission.</p>
</body>
</html>
"""
# 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'])
The only issue now is that if I upload multiple files, I get sent an email per file. Is there any way of collating them all into one email?

Related

Extracting attachment in an email which is an attachment inside an email using outlook api Python

I use the code below to extract the attachment from an email, but the problem is that I need to extract an attachment inside an email which is already an attachment of an email. It goes like this :
email -> email (as an attachment) -> attachment
Can someone help ? I have a shit ton of email attachment to extract...
The code I used:
from pathlib import Path #core python module
import win32com.client #pip install pywin32
# Create output folder
output_dir = Path.cwd() / "Output"
output_dir.mkdir(parents=True, exist_ok=True)
# Connect to outlook
outlook = win32com.client.Dispatch("Outlook.Application").GetNamespace("MAPI")
# Connect to folder
#inbox = outlook.Folders("youremail#provider.com").Folders("Inbox")
inbox = outlook.GetDefaultFolder(6)
# https://docs.microsoft.com/en-us/office/vba/api/outlook.oldefaultfolders
# DeletedItems=3, Outbox=4, SentMail=5, Inbox=6, Drafts=16, FolderJunk=23
# Get messages
messages = inbox.Items
for message in messages:
subject = message.Subject
body = message.body
attachments = message.Attachments
# Create separate folder for each message
target_folder = output_dir / str(subject)
target_folder.mkdir(parents=True, exist_ok=True)
# Write body to text file
Path(target_folder / "EMAIL_BODY.txt").write_text(str(body))
# Save attachments
for attachment in attachments:
attachment.SaveAsFile(target_folder / str(attachment))
I tried to add a loop, to get the item inside the item. It didn't work
The problematic lines of code are:
# Create separate folder for each message
target_folder = output_dir / str(subject)
target_folder.mkdir(parents=True, exist_ok=True)
Make sure that the Subject property value doesn't contain forbidden symbols. Windows (and linux) has a number of symbols forbidden to use in folder and file names. See What characters are forbidden in Windows and Linux directory names? for more information.
Second, you need to check the attachment type by checking the Attachment.Type property to make sure that you deal with a real file attached, not URL or linked attachments.
4096, 'Microsoft Outlook', "Cannot save the attachment. You don't have appropriate permission to perform this operation."
Make sure that you pass a valid file path to the SaveAsFile method. You must specify the full attachment file name including the name part. Most probably you are only specifying the directory name, but you need to concatenate the directory and file name (you may use the DisplayName property of the attachment object for the filename).

S3 PreSigned URL is cut when sent in an email

I have a script which generates an S3 PreSigned URL and sends it in an email.
The script works fine, but when the email is sent, it adds a new-line to the URL, which breaks it and makes it unusable in the email.
The only packages installed:
boto3
Jinja2
The script:
import boto3
from botocore.config import Config
from jinja2 import Environment, FileSystemLoader
from email.mime.multipart import MIMEMultipart
from email.mime.text import MIMEText
import smtplib
# AWS
my_config = Config(
region_name = 'eu-west-1'
)
s3 = boto3.client('s3', config=my_config)
bucket = "name of bucket"
# Jinja2
loader = FileSystemLoader('templates')
env = Environment(loader=loader)
email_template = env.get_template('test_template.html')
def create_presigned_url(bucket, object_name, expiration=259200):
response = s3.generate_presigned_url('get_object', Params={'Bucket': bucket, 'Key': object_name}, ExpiresIn=expiration)
return response
def sendEmail(download_link):
toEmail = 'me#email.com'
msg = MIMEMultipart('alternative')
title = 'Test email'
sender = 'me#email.com'
rendered_template = MIMEText(email_template.render({'download_link':download_link}), 'html')
msg['Subject'] = title
msg['From'] = sender
msg['To'] = toEmail
receivers = toEmail
msg.attach(rendered_template)
try:
smtpObj = smtplib.SMTP('mail.server.com', 25)
smtpObj.sendmail(sender, receivers, msg.as_string())
print ("Successfully sent email")
smtpObj.quit()
except Exception as e:
print (e, "Error: unable to send email")
if __name__ == "__main__":
selectedFile = 'file.txt'
# Download link
downloadURL = create_presigned_url(bucket, selectedFile)
# print(downloadURL)
# Send email
sendEmail(downloadURL)
Results
When I run the script, for some reason I get a newline somewhere inside of this long URL, which breaks the URL:
Here's the source from Outlook:
<meta http-equiv="Content-Type" content="text/html; charset=us-ascii">Download link: https://redacted/9%2FJOUw%3D&x-amz-security-token=IQoJb3JpZ2luX2VjEH0aCWV1LXdlc3QtMSJHMEUCIEBMYHD9wKhOfrR00jTv7RIcsRe3NbOU31QniJpEdps8AiEAi377qRmvQQXb5dXhRGJcXulFhRunGTSd0GRyGXHR2kMqzAQIdhAEGgwzNTgyODkxNTgxMTIiDH3bqAZMxVyKH3f6xyqpBL40WhPQMShoV8x1epn85Ml6qQ8Y1xdHe16xyoMWKqylbLGrndMFtYyOgs6LAlDvGJPrcF9xymGf8BqGsGHwCuWGdEcisxvwR%2FUoigjHBXP55fHpF%2FXnVupCRYDIVA5N%2BVOKW5%2BcljVN9KC3RKKvEeUncTGnXIaW5UHNAPiFSrgbbj9X%2FyBptkFmj5f4x2Zblm8crQS0rMTveCuoki3E06NO%2FKiDNiJQpF1vVphb%2F0spIR3CUxSx9HJHjvRBWTWQn9bmmT8rhp0lx%2Bzx9RLlpmE6hRRF6KBpNW%2B86y3EB%2BtMxVBuEhC5M1rCyjou6efK%2FA96wuwBN%2FmjD663vyZipiOGrj4yOFIMPklBu4L1SnfkxhZN8%2BNWXzwc%2B%2B5%2FNfL%2BVzyFpWS7TbGIM4A9TEvL3bPlgafvIl%2Fi24MOrN47UshpdpHGAjG20PBr0cbi75G7D%2B3UoSn%2Bzp0hZkAEACnwWtWtzEpVWbwatx%2FL1T8XF43o8OiKWqCfVxBjoZSc1itxRDOUqonYbCGY2Y0NlkXpvpHBZMcg7530dIFRBBxhTZo4RVXqkymTM4hEvDUw74R%2BDovr%2F%2BG5ji52Wpcng
954ESTpzMjOtuBXKcPtmEWTqx4au99ZP8lxbqKjq3BO%2FJLqrzTCPSEs6CTv7YbtzUqQ0r%2BkFyAU2RnpTTcYPJ5SD8ytlb4qUHb5RhEcn3bbJ5fsIRx%2B6q3LrhWkorDNKp5jh6oth1roRxXQM0swgN%2BzmwY6qQGnjWLAgUSUB9yf3heEdiFZo4DnC7ipW6BgsnkoeZJcPz5Ysx5PG4kzelCP89AsXQGD%2BtFqweusgWJVLo3dfyK3iLJ5myohn7mjSf1YVE%2B5CGlajc2HZl%2BoUOhI5gMMxpFXtpIL6jgTyY5r6ZwCKZ9g1afHO1kUF4VYir2M2BWYHTcB%2Bu8TANzoc15RJih8XmE%2FAWd%2FMQM7SQOQxsbmCiRSv5AeYMuok%2FSw&Expires=1668345190
I tried:
using | safe inside of my Jinja2 template.
I tried using the href HTML tag, no dice.
I don't know what else I can check and have no idea why it's happening. People mentioned this might be the cause: https://www.rfc-editor.org/rfc/rfc2822#section-2.1.1
It looks like the problem is related to max line length defined in the "Internet Message Format" RFC document 5322
2.1.1. Line Length Limits
There are two limits that this standard places on the number of characters in a line. Each line of characters MUST be no more than 998 characters, and SHOULD be no more than 78 characters, excluding the CRLF.
...
The more conservative 78 character recommendation is to accommodate the many implementations of user interfaces that display these messages which may truncate, or disastrously wrap, the display of more than 78 characters per line, in spite of the fact that such implementations are non-conformant to the intent of this specification (and that of [RFC2821] if they actually cause information to be lost). Again, even though this limitation is put on messages, it is encumbant upon implementations which display messages
Your line (with redacted information) has 961 characters, so adding those redacted information I assume you go over that limit of 998 characters.
Now, my thinking is that your local SMTP server is not splitting the line but the one on Amazon server may do that.
I assume that reducing the line length is not really an option :)
I would try with changing the markup, because now Outlook is looking for links and highlighting them in your message. I would try to add html markup for that with new line character inside, which hopefully will be ignored by the email client.
<a href="https://redacted/9%2FJOUw%3D&x-amz......
........">Download link</a>
try to change your jinja template to get something like
<meta http-equiv="Content-Type" content="text/html; charset=us-ascii">
Download link:
Download link
as you didn't add <a href= your link is interpretated as long text => and in long text editor can add line breaks

Using Lambda function to parse SES email with attachment and send to S3 bucket

SITUATION: I verified a domain name in AWS and set up an S3 bucket that recieves emails.
These emails contain a .csv file and are delivered to this bucket on a daily basis. I can verify the presence of the attachment by manually exploring the raw email. No problems.
DESIRED OUTCOME: I want to parse these emails, extract the attached .csv and send the .csv file to a destination S3 bucket (or destination folder within the same S3 bucket) so that I can later process it using a seperate Python script
ISSUE: I have written the Lambda function in Python and the logs show this executes successfully when testing yet no files appear in the destination folder.
There is an ObjectCreated trigger enabled on the source bucket which I believe should activate the function on arrival of a new email but this does not have any effect on the execution of the function.
See Lambda function code below:
import json
import urllib
import boto3
import os
import email
import base64
FILE_MIMETYPE = 'text/csv'
# destination folder
S3_OUTPUT_BUCKETNAME = 's3-bucketname/folder'
print('Loading function')
s3 = boto3.client('s3')
def lambda_handler(event, context):
#source email bucket
inBucket = event['Records'][0]['s3']['bucket']['name']
key = urllib.parse.quote(event['Records'][0]['s3']['object']['key'].encode('utf8'))
try:
response = s3.get_object(Bucket=inBucket, Key=key)
msg = email.message_from_string(response['Body'].read().decode('utf-8'))
except Exception as e:
print(e)
print('Error retrieving object {} from source bucket {}. Verify existence and ensure bucket is in same region as function.'.format(key, inBucket))
raise e
attachment_list = []
try:
#scan each part of email
for message in msg.get_payload():
# Check filename and email MIME type
if (msg.get_filename() != None and msg.get_content_type() == FILE_MIMETYPE):
attachment_list.append ({'original_msg_key':key, 'attachment_filename':msg.get_filename(), 'body': base64.b64decode(message.get_payload()) })
except Exception as e:
print(e)
print ('Error processing email for CSV attachments')
raise e
# if multiple attachments send all to bucket
for attachment in attachment_list:
try:
s3.put_object(Bucket=S3_OUTPUT_BUCKETNAME, Key=attachment['original_msg_key'] +'-'+attachment['attachment_filename'] , Body=attachment['body'])
except Exception as e:
print(e)
print ('Error sending object {} to destination bucket {}. Verify existence and ensure bucket is in same region as function.'.format(attachment['attachment_filename'], S3_OUTPUT_BUCKETNAME))
raise e
return event
Unfamiliar territory so please let me know if further information is required.
EDIT
As per comments I have checked the logs. Seems that function is being invoked but the attachment is not being parsed and sent to destination folder. It's possible that there's an error in the Python file itself.

AWS Lambda unable to send email through AWS SES

I have verified the following
AWS SES isn't in Sandbox. I can send email via console to non-verified email ids.
My Lambda function has a role attached with full access to SES and Lambda (since its initial basic testing gave full permissions)
The following below a basic code from AWS documentation, just hard coded my email id. Yet I can't receive any email. The lambda code runs successfully but I don't receive emails.
import json
import os
import boto3
from botocore.exceptions import ClientError
from email.mime.multipart import MIMEMultipart
from email.mime.text import MIMEText
from email.mime.application import MIMEApplication
print('Loading function')
def lambda_handler(event, context):
print("Received event: " + json.dumps(event, indent=2))
#print("value1 = " + event['key1'])
#print("value2 = " + event['key2'])
#print("value3 = " + event['key3'])
#return event['key1'] # Echo back the first key value
#raise Exception('Something went wrong')
SENDER = "[redacted email]"
RECIPIENT = event['email']
CONFIGURATION_SET = "ConfigSet"
AWS_REGION = "us-east-2"
SUBJECT = "Contact Us Form Details"
# The email body for recipients with non-HTML email clients.
BODY_TEXT = "Hello,\r\nPlease see the attached file for a list of customers to contact."
# The HTML body of the email.
BODY_HTML = """\
<html>
<head></head>
<body>
<h1>Hello!</h1>
<p>Please see the attached file for a list of customers to contact.</p>
</body>
</html>
"""
# The character encoding for the email.
CHARSET = "utf-8"
# Create a new SES resource and specify a region.
client = boto3.client('ses',region_name='us-east-2')
# Create a multipart/mixed parent container.
msg = MIMEMultipart('mixed')
# Add subject, from and to lines.
msg['Subject'] = "Contact Us Form Details"
msg['From'] ="[redacted email]"
msg['To'] = "[redacted email]"
# 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="[redacted email]",
Destinations=[
"[redacted email]"
],
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'])
Attaching my cloud watch logs for reference
If your code is really what you have displayed to us, then the reason that it is not sending the email is because half your code is not being executed.
def lambda_handler(event, context):
print("Received event: " + json.dumps(event, indent=2))
#print("value1 = " + event['key1'])
#print("value2 = " + event['key2'])
#print("value3 = " + event['key3'])
#return event['key1'] # Echo back the first key value
#raise Exception('Something went wrong')
SENDER = "[redacted email]"
RECIPIENT = event['email']
CONFIGURATION_SET = "ConfigSet"
AWS_REGION = "us-east-2"
SUBJECT = "Contact Us Form Details"
# The email body for recipients with non-HTML email clients.
BODY_TEXT = "Hello,\r\nPlease see the attached file for a list of customers to contact."
When AWS Lambda executes the function, it calls lambda_handler(). As per Python formatting, it will execute all indented lines since they form part of the function. This includes your print() statement.
However, starting with the BODY_TEXT = ... line, there is no indenting. This means that the code is part of the "main" program, and not part of the lambda_handler() function. It would be executed when the Lambda container is first instantiated, but not when the function is triggered.
Bottom line: If this is your actual code, you need to fix your indents.
If you are not getting any errors from when executing the lambda, then most probably you are not hitting the SES API. From what I see in your code, you are missing an Access Key Id and Secret Access Key. Try configuring your boto client like this:
client = boto3.client(
'ses',
region_name=region,
aws_access_key_id='aws_access_key_string',
aws_secret_access_key='aws_secret_key_string'
)
Also make sure that your lambda is deployed in the same region as your SES. I see you are using us-east-2.
Another discrepancy I see, which is also in the documentation is that in the official AWS documentation, Destinations is actually Destination. Try it without the 's'.
Can you also paste the cloudwatch logs for the lambda. I see it should print the message Id upon success. Does it?

How to read only the 1st email body of the msg file, excluding the mails that are attached to that msg file

I am currently trying to figure out how to parse all the msg files I have stored in a specific folder and then save the body text to a dataframe but when I'm trying to extract the body of the emaill it is also extracting the emails that are attached to it. I want to extract only the body of the first email that is present in the msg file.
#src-code:https://stackoverflow.com/questions/52608069/parsing-multiple-msg-files-and-storing-the-body-text-in-a-csv-file
#reading multiple .msg files using python
from pathlib import Path
import win32com.client
outlook = win32com.client.Dispatch("Outlook.Application").GetNamespace("MAPI")
# Assuming \Documents\Email Reader is the directory containg files
for p in Path(r'C:\Users\XY\Documents\Email Reader').iterdir():
if p.is_file() and p.suffix == '.msg':
msg = outlook.OpenSharedItem(p)
print(msg.Body)
I had a similar requirement. Full code is here:
https://medium.com/#theamazingexposure/accessing-shared-mailbox-using-exchangelib-python-f020e71a96ab
For you purpose I think this snippet is going to work. It reads the first message with a specific subject line:
from exchangelib import Credentials, Account, FileAttachment
credentials = Credentials('First_Name.Last_Name#some_domain.com', 'Your_Password_Here')
account = Account('First_Name.Last_Name#some_domain.com', credentials=credentials, autodiscover=True)
filtered_items = account.inbox.filter(subject__contains='Your Search String Here')
print("Getting latest email from Given Search String...")
for item in account.inbox.filter(subject__contains='Your Search String Here').order_by('-datetime_received')[:1]:
print(item.subject, item.text_body.encode('UTF-8'), item.sender, item.datetime_received) #body of email is extracted using:: item.text_body.encode('UTF-8')
from exchangelib import Credentials, Account, FileAttachment
credentials = Credentials('First_Name.Last_Name#some_domain.com','Your_Password_Here')
account = Account('First_Name.Last_Name#some_domain.com', credentials=credentials, autodiscover=True)
unread_mails = account.inbox.filter(is_read=False)
# ur unread mail list
unread_mail_list = [mail for mail in unread_mails]
# get text body of the latest unread mail
mail_body = unread_mail_list[0].text_body

Categories