Send Reply to email thread - python

I'm trying to reply to an email based on the following criteria:
Scan the inbox for unseen mails with specific Subject content, if there is mails that satisfy those criteria then: send back an reply message to the sender saying "something", if those criteria are not met then: send back an reply message to the sender saying "something".
This is what i came up with so far:
import imaplib
import email
import smtplib
username = 'sample#gmail.com'
password = 'xxxx'
imap_server = imaplib.IMAP4_SSL('smtp.gmail.com')
imap_server.login(username, password)
imap_server.select('INBOX')
result, data = imap_server.search(None, '(UNSEEN)')
email_ids = data[0].split()
for email_id in email_ids:
result, data = imap_server.fetch(email_id, "(RFC822)")
raw_email = data[0][1]
email_message = email.message_from_bytes(raw_email)
subject = email_message["Subject"]
if subject == "SOME SPECIFIC CONTENT":
reply = email.message.EmailMessage()
reply["To"] = email_message["From"]
reply["Subject"] = "Re: " + email_message["Subject"]
reply["In_Reply-To"] = email_message["From"]
server = smtplib.SMTP('smtp.gmail.com', 587)
server.ehlo()
server.starttls()
server.login(username, password)
server.sendmail(username, reply["In_Reply-To"], 'Subject: Criteria met\n\nThank you.')
server.quit()
else:
reply = email.message.EmailMessage()
reply['To'] = email_message['From']
reply['Subject'] = "RE:" + email_message['Subject']
reply["In_Reply-To"] = email_message["From"]
server = smtplib.SMTP('smtp.gmail.com', 587)
server.ehlo()
server.starttls()
server.login(username, password)
server.sendmail(username, reply["In_Reply-To"], 'Subject: Criteria not met\n\Thank you.')
print('Sending email')
server.quit()
imap_server.close()
It sends the email but without the desired thread, just sends a new email and not actually replying back to the sender.
Any suggestion on how to modify the code so it actually send an reply with the desired thread?
Thank you in advance.

Like the comment mentions, you should use the Message-Id of the original message, not the sender address.
Also, you should obey Reply-To: and add References:.
reply = email.message.EmailMessage()
reply["To"] = email_message["Reply-To"] or email_message["From"]
reply["Subject"] = "Re: " + email_message["Subject"]
reply["In_Reply-To"] = email_message["Message-Id"]
reply["References"] = (email_message["References"] or "") + " " + email_message["Message-Id"]
Properly speaking, the References: header should be trimmed from the middle if it's too long.
Some vendors have their own nonstandard threading extensions; in particular, Microsoft's Thread-Id: etc headers are probably best ignored.

Related

Change email credentials when looping smtp python

I am working with the below code to send emails to customer and as you guys know there is daily sending limits set by different companies.
What I want to achieve is to change email credentials before reaching limit but continue with the recipient list.
For example: I have 5 email credentials each email id will 50 emails and will change automatically.
Code I work with:
import smtplib
li = ["xxxxx#gmail.com", "yyyyy#gmail.com"]
for dest in li:
s = smtplib.SMTP('smtp.gmail.com', 587)
s.starttls()
s.login("sender_email_id", "sender_email_id_password")
message = "Message_you_need_to_send"
s.sendmail("sender_email_id", dest, message)
s.quit()
Get the index of the destination in its list, and transform that into an index into the credentials list.
for i, dest in enumerate(li):
if i//50 >= len(credentials):
print("Ran out of credentials")
break
creds = credentials[i//50]
// use credentials to send mail
clients = ["xxxxx#gmail.com", "yyyyy#gmail.com"]
chunk_size = 50
chunks = (clients[i:i+chunk_size] for i in range(0,len(clients), chunk_size))
creds = [("sender_email_id_1", "sender_email_id_password_1"), ("sender_email_id_2", "sender_email_id_password_2")]
for i,chunk in enumerate(chunks):
try:
user, pw = creds[i]
except IndexError:
print("Ran out of credentials")
raise
for client in chunk:
s = smtplib.SMTP('smtp.gmail.com', 587)
s.starttls()
s.login(user, pw)
message = "Message_you_need_to_send"
s.sendmail(user, client, message)
s.quit()
If you'd rather not throttle yourself, but would like to keep trying to send as many emails as possible:
clients = ["xxxxx#gmail.com", "yyyyy#gmail.com"]
creds = [("sender_email_id_1", "sender_email_id_password_1"), ("sender_email_id_2", "sender_email_id_password_2")]
for cred,client in zip(itertools.cycle(creds), clients):
user, pw = creds
s = smtplib.SMTP('smtp.gmail.com', 587)
s.starttls()
s.login(user, pw)
message = "Message_you_need_to_send"
s.sendmail(user, client, message)
s.quit()
The following uses a generator nextcred to loop over the credentials in a list until you have sent all the messages. It wraps back to the first pair after you have looped over the whole list.
We use one pair to send 50 messages, then log out and back in with the next pair of credentials.
import smtplib
def nextcred():
credentials = [('user', 'password'), ('plugh', 'xyzzy'), ('alfred', 'what me worry?')]
while True:
for tup in credentials:
yield tup
li = ["xxxxx#gmail.com", "yyyyy#gmail.com"]
cred = nextcred()
s = None
for idx, dest in enumerate(li):
if (idx % 50) == 0:
if s:
s.quit()
account, passw = next(cred)
s = smtplib.SMTP('smtp.gmail.com', 587)
s.starttls()
s.login(account, passw)
message = "Message_you_need_to_send"
s.sendmail("sender_email_id", dest, message)
s.quit()
As an aside, I hope you are not really constructing your SMTP messages by pasting together strings. The Python email library takes care of a mound of corner cases and complications which are hard to get right and impossible to guess how to solve if you are not intimately familiar with SMTP and MIME.

Use Python to send SMS as a given name

How can I send an SMS email as a name such as Joe Doe or (846) 596-2256?
I can send an SMS message to a phone number with any email I want with this code here
import smtplib
to = 'xxxxxxxxxx#xxxx.com'
sender_user = 'xxx#provider.com'
sender_pwd = 'xxx'
fake_email = 'fake#fake.com'
fake_name = 'Fake Name'
message = 'This is a test message!'
smtpserver = smtplib.SMTP("smtp.emailprovider.com", 587)
smtpserver.ehlo()
smtpserver.starttls()
smtpserver.ehlo
smtpserver.login(sender_user, sender_pwd)
header = f'To: {to}\nFrom: "{fake_name}" <{fake_email}>\nSubject: \n'
msg = header + '\n' + message + '\n\n'
smtpserver.sendmail(sender_user, to, msg)
smtpserver.close()
And it appears on the phone like this
Is it possible to remove the #domain.com part? If I do not enter a valid email (Containing a *#*.*) the text message will either not go through entirely or appear as a text message sent by 6245 which after a bit of research is the number which Verizon (my carrier) will send an invalid SMS as. Can I do this with just a python script?

smtplib repeating send unnecessarily

I'm running a script that will both fetch emails (imaplib) and will send alerts back to my personal email using smtplib. I am running it on my raspberry pi 24/7 and so when I am not at home I want to check that the program is still running fine.
Here are the functions:
def get_alert():
global subject
user = alert_email
password = alert_email_password
mail = imaplib.IMAP4_SSL('imap.gmail.com')
mail.login(user, password)
mail.list()
mail.select('inbox')
result, data = mail.uid('search', None, 'UNSEEN')
i = len(data[0].split())
for x in range(i):
latest_email_uid = data[0].split()[x]
result, email_data = mail.uid('fetch', latest_email_uid, '(RFC822)')
raw_email = email_data[0][1]
raw_email_string = raw_email.decode('utf-8')
email_message = email.message_from_string(raw_email_string)
subject = str(email.header.make_header(email.header.decode_header(email_message['Subject'])))
print(subject)
return subject
mail.logout()
def send_alert(subj, msg):
server = smtplib.SMTP('smtp.gmail.com:587')
server.ehlo()
server.starttls()
server.login(alert_email, alert_email_password)
message = 'Subject: {}\n\n{}'.format(subj, msg)
server.sendmail(from_addr=alert_email, to_addrs=personal_email, msg=message)
server.quit()
Here's the loop:
while True:
get_alert()
if subject == 'check': # check that program is still running
send_alert(subj='still running', msg='still running')
if subject == ...
So what happens is that it will get the 'check' email perfectly, and prints it out only once as it should. Yet every loop sends me 'still running' every time it runs despite the email being marked as read and having no more unread emails. Shouldn't subject be None if there are no unread emails?? I've tried manually setting subject to none and marking all emails as read after returning subject. Not sure what is happening, if you can help I greatly appreciate. this has been driving me nuts all day :/

Python Email Notification Not Sending

This code is supposed to send an email to a specified address and when I hard code the "TEXT" & "SUBJECT" it seems to send fine but when I create it as a function and call it it never sends the email and never prints the "Notification Sent" message. What am I missing?
Tried hard coding the TEXT and SUBJECT and it sends fine! NOTE: YOU MUST ENABLE LESS SECURE APPS WHEN USING GMAIL!
import smtplib
class email_thing:
def email_notification(self,SUBJECT,TEXT):
TO = 'email#example.com'
self.SUBJECT = SUBJECT
self.TEXT = TEXT
gmail_sender = 'email#example.com'
gmail_passwd = 'examplepassword'
server = smtplib.SMTP('smtp.gmail.com', 587)
server.ehlo()
server.starttls()
server.login(gmail_sender, gmail_passwd)
return self.SUBJECT
return self.TEXT
BODY = '\r\n'.join(['To: %s' % TO,
'From: %s' % gmail_sender,
'Subject: %s' % SUBJECT,
'',TEXT])
try:
server.sendmail(gmail_sender, [TO], BODY)
print ('Notification Sent!')
except:
print ('error sending mail')
server.quit()
test_send = email_thing()
test_send.email_notification(SUBJECT ='Test Email',TEXT = 'This is a test from python!')
Remove
return self.SUBJECT
return self.TEXT
return exits method at once so code after return is never executed.

In python's smtplib why isn't the subject or From field set?

can anyone see why the following code sends emails successfully but it shows up as being from the email address of the sender instead of the name of the sender in the recipients inbox, and the subject shows up as "No Subject" in their inbox. Thanks in advance.
def send_email(destination, subject, message):
from_who = "My Name"
to_send = """\From: %s\nTo: %s\nSubject: %s\n\n%s""" % (from_who, destination, subject, message)
try:
server = smtplib.SMTP("smtp.gmail.com", 587)
server.ehlo()
server.starttls()
server.login(my_email_addr, my_pwrd)
server.sendmail(from_who, destination, message)
server.close()
except:
print "failed"
If you want to use SMTP in python, you need to send the data as a dictionary.
from email.parser import Parser
# This will parse out your to-, from-, and subject fields automatically
headers = Parser().parsestr(to_send)
# This will take care of the to- and from-fields for you
server.send_message(headers)
test.py
from email.parser import Parser
from_whom = "hello#example.com"
destination = "world#example.com"
subject = "Foobar!"
message = "Bar bar binks"
to_send = """From: %s\nTo: %s\nSubject: %s\n\n%s""" % (from_whom, destination, subject, message)
print(to_send)
headers = Parser().parsestr(to_send)
print(headers["To"]) # world#example.com
print(headers["From"]) # hello#example.com
print(headers["Subject"]) # Foobar!
EDIT
Alternatively, you could do this:
to_send = string.join((
"From: %s" % from_whom,
"To: %s" % destination,
"Subject: %s" % subject,
"",
message
), "\r\n")
# ...
server.sendmail(from_whom, [destination], to_send)
# ...
I think the other way is cleaner, but this is up to you.

Categories