I'm trying to delete emails by UID. It's a hotmail email account I'm accessing.
Here's what I'm doing:
1. Connect to Email
imap = imaplib.IMAP4_SSL('imap-mail.outlook.com')
imap.login('my_email#hotmail.com', "password")
2. Get UID from emails
resp, _ = imap.select('Inbox')
mbox_response, msgnums = imap.search( None,'FROM', 'email#sender.com')
messages = [] #Appending UID to this dictionary
for num in msgnums[0].split():
msg_uid = imap.fetch(num, 'UID')
messages.append({'uid':imap.fetch(num, 'UID')})
3. Print UIDs
print(messages)
I get the following output:
[{
'uid': ('OK', [b'1 (UID 111)']),
'uid': ('OK', [b'2 (UID 114)'])
}]
4. How do I delete?
How do I use these UIDs to delete the specific message?
I've tried this without success...
for m in messages:
imap.store(m['uid'],'+X-GM-LABELS', '\\Trash')
I get the following error:
TypeError: can't concat tuple to bytes
from imap_tools import MailBox
with MailBox('imap.mail.com').login('test#mail.com', 'pwd', 'INBOX/test') as mailbox:
# DELETE all messages from current folder (INBOX/test)
mailbox.delete([msg.uid for msg in mailbox.fetch()])
https://github.com/ikvk/imap_tools
Related
I've connected a SQL query to Python and am trying to automate an email with attachment if the SQL query returns results. This query will show the discrepancies between our prices and the prices our client is selling our products at.
If there are differences between the 'Unit Price' and 'Selling Price', I want to email these to my director. However, if there are no differences, then the query will return 0 results and I do not want an empty email to be sent out.
My difficulty in this is that the python script is sending the attachment even if the query is returning no results. I only want to send the attachment if my query is returning results.
Any help on this would be greatly appreciated!
sql_query = pd.read_sql_query('''
SELECT SaleH.[Order No], SaleH.[Reference], SaleL.[Product code], SaleL.[Description], SaleL.[Quantity], SaleL.[Unit Price], SaleP.[Unit Price] AS 'Selling Price'
FROM [Sales Header] SaleH
INNER JOIN [Sales Line] SaleL ON SaleH.[Order No] = SaleL.[Order No]
LEFT JOIN [Sales Price] SaleP ON SaleP.[Product Code] = SaleL.[Product Code] AND SaleH.[Customer No] = SaleP.[Customer No]
WHERE SaleH.[Customer No] = 'Cust01' AND SaleH.[Date] >DATEADD(DD,-1,getdate()) AND SaleP.[Unit Price] != SaleL.[Unit Price]
''' ,conn)
df = pd.DataFrame(sql_query)
df.to_csv (r'G:\Customer Folder\Customer_Sales_Orders.csv', index = False)
outlook = win32. Dispatch('outlook.application')
email = outlook.CreateItem(0)
mail_from = "Sender"
mail_to = "Recipient"
mail_subject = "Customer Sales Orders"
mail_attachment = 'Customer_Sales_Orders.csv'
mail_attachment_name = "Customer_Sales_Orders" +'.csv'
This will do:
results = pd.read_csv('Data.csv') # count no. of lines
if len(results))> 0:
#sendemail
from_address = "<from which email>>"
to_address = "<<to which email>>"
# Create message container - the correct MIME type is multipart/alternative.
msg = MIMEMultipart('alternative')
msg['Subject'] = "Customer ha made purchases in the last 24 hours for
{}".format(date.today())
msg['From'] = from_address
msg['To'] = to_address
# Create the message (HTML).
html = """\
This is an automated email.
We are sending an email using Python and Gmail, how fun! We can fill this with html, and gmail supports a decent range of css style attributes too - https://developers.google.com/gmail/design/css#example.
"""
# Record the MIME type - text/html.
part1 = MIMEText(html, 'html')
# Attach parts into message container
msg.attach(part1)
# Credentials
username = '<your email id>'
password = '<google_app_password>'
# Sending the email
## note - this smtp config worked for me, I found it googling around, you may have to tweak the # (587) to get yours to work
server = smtplib.SMTP('smtp.gmail.com', 587)
server.ehlo()
server.starttls()
server.login(username,password)
server.sendmail(from_address, to_address, msg.as_string())
server.quit()
I am using imap_tools to access and process our business emails. I would like to filter out multiple different from_ messages.
Here's working code for filtering out one from_ address. This returns all emails within the date range except those from notifications#stripe.com
from imap_tools import MailBox, A, AND, OR, NOT
import datetime as dt
from bs4 import BeautifulSoup
username = "info#mysite.co.uk"
password = "mypasword"
imap_server = "mysite.co.uk"
# Get date, subject and body len of all emails from INBOX folder
with MailBox(imap_server).login(username, password) as mailbox:
for msg in mailbox.fetch(
AND(NOT(from_="notifications#stripe.com"), date=dt.date(2022, 9, 9))
):
# print(msg.date, msg.subject, msg.html)
if msg.html:
soup = BeautifulSoup(msg.html, "html.parser")
print(msg.from_)
print(msg.subject)
print(msg.date)
print(soup.prettify)
print(180 * "=")
This is what I have tried:
# Get date, subject and body len of all emails from INBOX folder
with MailBox(imap_server).login(username, password) as mailbox:
for msg in mailbox.fetch(
AND(
NOT(from_=["notifications#stripe.com", "noreply#wise.com"]),
date=dt.date(2022, 9, 9),
)
):
As per the docs one should pass in a list of str. from_: str | List[str] | None = None
But when I try and pass in a list of email addresses that I don't want to fetch, it just returns all the emails within the date range.
Any ideas? Thanks in advance!
Seems it is limitation of your server.
I have checked on YANDEX - the same.
On another server it works.
I get this error when sending emails via smptplib in Python to a certain list
SMTPRecipientsRefused: {'': (421, b'4.7.0 Too many protocol errors (6) on this connection, closing transmission channel.')}?
I'm using Office365 SMTP details and a snippet of the code is below:-
import smtplib, ssl
from email.message import EmailMessage
import getpass
ids = df['IDs']
emails_to = df['Emails']
namesofcompanies = df["CompanyNames"]
sendfrom = df["SenderList"]
date_7days = (datetime.now() + timedelta(days=7)).strftime('%d/%m/%Y')
date_14days = (datetime.now() + timedelta(days=13)).strftime('%d/%m/%Y')
email_pass = input() #Office 365 password
context=ssl.create_default_context()
for i in range(len(emails_to)): # iterate through the records
# for every record get the name and the email addresses
ID = str(ids[i])
Emaitstosendto = emails_to[i]
companynames = namesofcompanies[i]
tosendfrom = sendfrom[i]
if my_files_dict.get(ID): #Looks for attachments in the same folder with same name as the corresponding record
smtp_ssl_host = 'smtp.office365.com'
smtp_ssl_port = 587
email_login = "xxx#xxx.com" #Office 365 email
email_from = tosendfrom
email_to = Emaitstosendto
msg = MIMEMultipart()
msg['Subject'] = "Received Emails between "+date_7days+" - "+date_14days
msg['From'] = email_from
msg['To'] = email_to
msg['X-Priority'] = '2'
text = ("XXXX,\n"
f"xxxxxx\n\n")
msg.attach(MIMEText(text))
filename = my_files_dict.get(ID)#Files in the folder matching the ID
fo = open(filename,'rb')
s2 = smtplib.SMTP(smtp_ssl_host, smtp_ssl_port)
s2.starttls(context=context)
s2.login(email_login, email_pass)
attachment = email.mime.application.MIMEApplication(fo.read(),_subtype="xlsx")
fo.close()
attachment.add_header('Content-Disposition','attachment',filename=filename)
msg.attach(attachment)
s2.send_message(msg)
s2.quit()
On average, I will be sending emails to a list separated by a semi-colon(;) of about 8 emails per record. This means that for each attachment, I'll send to about 8 emails and I'm to do it for about 70 of such contacts. In total, that will be about 560 emails. Nothing gets sent out I get the above error the moment I log in. On the contrary, when I try test sending it to a list of 3 emails in the test emails column, the same emails go out very well. Can anyone point to where I may not be getting it right? I suspect either the list of emails is too long or is something with the email addresses thus the protocol error? Is this an SMTPlib limitation?
What you specify in MIMEMultipart() is what appears in the message header, but this is not always equal to the list of recipients. You can try to change server.send_message(msg) to server.sendmail(sender,recipients,msg.as_string())
Keep in mind that sendmail() requires a list of recipients, whereas msg['To'] should be set as one string, so if your variable email_to is comma separated, you should write it like:
s2.sendmail(email_from,email_to.split(','),msg.as_string())
More details about sendmail() can be found here.
I resolved this error by creating a list and joined all addresses from a tuple into a string, using a comma character as separator.
family = the list of all recipients' email addresses
family = [
'name1#example.com',
'name2#example.com',
'name3#example.com',
'name4#example.com',
'name5#example.com',
'name6#example.com',
'name7#example.com',
'name8#example.com'
]
msg['To'] =', '.join(family)
so I'm working on something that uses regex to search something from an email, which is fetched via imaplib module. Right now I can't get it to work, even after using str() function.
result, data = mail.fetch(x, '(RFC822)')
eemail = email.message_from_bytes(data[0][1])
print(str(eemail))
trying to regex it:
print(re.search("button", eemail))
Regex gives me no matches even after making the email a string object.
This is what I use:
import imaplib
import email
import re
mail = imaplib.IMAP4_SSL(SMTP_SERVER, SMTP_PORT)
mail.login(FROM_EMAIL,FROM_PWD)
mail.select('inbox')
status, response = mail.search(None, '(UNSEEN)')
unread_msg_nums = response[0].split()
for e_id in unread_msg_nums:
_, response = mail.fetch(e_id, '(UID BODY[TEXT])')
b = email.message_from_string(response[0][1])
if b.is_multipart():
for payload in b.get_payload(decode=True):
print(re.search("button", payload.get_payload(decode=True)))
else:
print(re.search("button", b.get_payload(decode=True)))
Below is my code and I am hoping someone can help me with the cleaning up the code and making it more effiencient. Basically, the code should iterate through all the volumes in my AWS account and then list all untagged volumes and then send out an email. However, it times out when running it as a lambda function in AWS but if i run it locally, it will take over 30 mins to complete (however it does complete). Im sure its iterating through things it doesnt need.
Also if I print the ec2_instances list, I can see duplicate values, so I want to only have unique values so that its not repeating the script for each ec2 instance.
import logging
import boto3
from smtplib import SMTP, SMTPException
from email.mime.text import MIMEText
logger = logging.getLogger()
logger.setLevel(logging.INFO)
session = boto3.Session(profile_name="prod")
client = session.client('ec2')
untagged_volumes = []
detached_volumes = []
ec2_instances = []
response = client.describe_volumes()
for volume in response['Volumes']:
if 'Tags' in str(volume):
continue
else:
if 'available' in str(volume):
detached_volumes.append(volume['VolumeId'])
else:
untagged_volumes.append(volume['VolumeId'])
untagged_volumes.append(volume['Attachments'][0]['InstanceId'])
ec2_instances.append(volume['Attachments'][0]['InstanceId'])
unique_instances = list(set(ec2_instances))
# Create the msg body.
msg_body_list = []
for instance in unique_instances:
desc_instance = client.describe_instances()
# append to the msg_body_list the lines that we would like to show on the email
msg_body_list.append("VolumeID: {}".format(desc_instance['Reservations'][0]['Instances'][0]['BlockDeviceMappings'][0]['Ebs']['VolumeId']))
msg_body_list.append("Attached Instance: {}".format(desc_instance['Reservations'][0]['Instances'][0]['InstanceId']))
# if there are tags, we will append it as singles lines as far we have tags
if 'Tags' in desc_instance['Reservations'][0]['Instances'][0]:
msg_body_list.append("Tags:")
for tag in desc_instance['Reservations'][0]['Instances'][0]['Tags']:
msg_body_list.append(" Key: {} | Value: {}".format(tag['Key'], tag['Value']))
# in case we don't have tags, just append no tags.
else:
msg_body_list.append("Tags: no tags")
msg_body_list.append("--------------------")
# send email
mail_from = "xxx#xxx.com"
mail_to = 'xxx#xxx.com'
msg = MIMEText("\n".join(msg_body_list))
msg["Subject"] = "EBS Tagged Instance Report for"
msg["From"] = mail_from
msg["To"] = mail_to
try:
server = SMTP('xxx.xxx.xxx.xxx', 'xx')
server.sendmail(mail_from, mail_to.split(','), msg.as_string())
server.quit()
print('Email sent')
except SMTPException:
print('ERROR! Unable to send mail')
Lambda functions have a time limit of 15 minutes. That is the reason for the timeout - if you need to run scripts for longer, look up AWS Fargate.