How can I see what labels an email has?
mail = imaplib.IMAP4_SSL('imap.gmail.com')
mail.login('myaccountxyz#gmail.com', mypassword)
mail.select("my-folder") # finds emails with this label
result, data = mail.uid('search', None, 'all')
for email_uid in data[0].split():
result, data_single = mail.uid('fetch', email_uid, '(RFC822)')
raw_email = data_single[0][1]
email_message = email.message_from_string(raw_email)
sender = email_message['From']
# get list of this email's labels
I haven't tried this code myself, but according to Google IMAP Extensions, you should be able to just fetch the X-GM-LABELS item:
typ, dat = mail.uid('fetch', email_uid, 'X-GM-LABELS')
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 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)
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
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)))
I'm using the following code to download all my emails from gmail, but unfortunately, the total number of emails returned does not match the total number of emails in the account. In particular, I'm able to get the first 43 messages, but I count 20+ more in the inbox that are missed. Perhaps this is some sort of limit on the number that can be pulled back(?). Thanks in advance for any assistance provided!
import imaplib, email, base64
def fetch_messages(username, password):
messages = []
conn = imaplib.IMAP4_SSL("imap.gmail.com", 993)
conn.login(username, password)
conn.select()
typ, data = conn.uid('search', None, 'ALL')
for num in data[0].split():
typ, msg_data = conn.uid('fetch', num, '(RFC822)')
for response_part in msg_data:
if isinstance(response_part, tuple):
messages.append(email.message_from_string(response_part[1]))
typ, response = conn.store(num, '+FLAGS', r'(\Seen)')
return messages
I use the following to get all email messages.
resp,data = mail.uid('FETCH', '1:*' , '(RFC822)')
and to get all the ids I use:
result, data = mail.uid('search', None, "ALL")
print data[0].split()
gives:
['1', '2', '3', '4', '5', '6', '7', '8', '9', '10', ... etc ]
EDIT
In my case the follow returns 202 dates which is in excess of what the OP is looking for and is the correct number.
resp,data = mail.uid('FETCH', '1:*' , '(RFC822)')
messages = [data[i][1].strip() for i in xrange(0, len(data), 2)]
for msg in messages:
msg_str = email.message_from_string(msg)
print msg_str.get('Date')