smtplib repeating send unnecessarily - python

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 :/

Related

Send Reply to email thread

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.

How do i decode a link from an email using imaplib and Python?

I have got a code that uses "imaplib" to search for a specific email and link, everything works fine, it successfully gets the link but once I actually try to use the link extracted from the email to make a get request, it doesn't work.
I belive it's something to do with encoding/decoding?
Any help would be appreciated!
This is the code:
def get_email_token(box):
status, messages = mail.select(box)
messages = int(messages[0])
for i in range(messages, messages-10, -1):
res, msg = mail.fetch(str(i), "(RFC822)")
for __ in msg:
raw_email = msg[0][1]
raw_email_string = raw_email.decode('utf-8')
email_message = email.message_from_string(raw_email_string)
email_from = str(email.header.make_header(email.header.decode_header(email_message['From'])))
subject = str(email.header.make_header(email.header.decode_header(email_message['Subject'])))
if "noreply#discord.com" in email_from and "Password Reset Request for Discord" in subject:
# Body details
for part in email_message.walk():
if part.get_content_type() == "text/plain":
body = part.get_payload(decode=True).decode()
for url in re.findall(r"https:\/\/click\.discord\.com\/ls\/click\?upn=.+", body):
return str(url)
url = get_email_token("inbox")
response = requests.head(url, allow_redirects=True).url
print(response)
It should return something in the lines of "https://discord.com/reset#token=" but instead I get the same link back.

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.

Windows batch file Infinite Loop hang while running Python file

I have a very simple Windows batch file that should run Python, wait 5 seconds, echo searching, loop.
The Python file is checking my email and either creating files or deleting them and then emailing me when conditions are correct for me to trade.
It works great but overnight I wake to see it is sitting stalled. If I press enter it starts up again and runs for some time.
Batch code is
:loop
timeout 5
"C:\Anaconda3\python.exe" "TValert.py"
echo "Scan Complete"
goto loop
and python code is
import imaplib,email,time
import smtplib
import os.path
from os import path
#mail imap
user = 'Trader#gmail.com'
pwd = 'password'
imap_url = 'imap.gmail.com'
con = imaplib.IMAP4_SSL (imap_url)
con.login(user,pwd)
con.select('INBOX')
def deleteEmail(user, pwd, IMAP):
typ, data = con.search(None, 'ALL')
for num in data[0].split():
con.store(num, '+FLAGS', r'(\Deleted)')
con.expunge()
print("Scanning Email....")
time.sleep(1.5)
result, no = con.search(None,'(FROM "god" SUBJECT "Come Home")')
result, long = con.search(None,'(FROM "tradingview" SUBJECT "Rosie Long")')
result, short = con.search(None,'(FROM "tradingview" SUBJECT "Rosie Short")')
result, close_long = con.search(None,'(FROM "tradingview" SUBJECT "Rosie Close Long")')
result, close_short = con.search(None,'(FROM "tradingview" SUBJECT "Rosie Close Short")')
result, TwoRiskOff = con.search(None,'(FROM "tradingview" SUBJECT "$2 Risk Off")')
result, NineRiskOff = con.search(None,'(FROM "tradingview" SUBJECT "$9 Risk Off")')
result, TwoWhite = con.search(None,'(FROM "tradingview" SUBJECT "$2 White")')
result, NineWhite = con.search(None,'(FROM "tradingview" SUBJECT "$9 White")')
result, TwoBlack = con.search(None,'(FROM "tradingview" SUBJECT "$2 Black")')
result, NineBlack = con.search(None,'(FROM "tradingview" SUBJECT "$9 Black")')
if long != no:
if path.exists("Long.txt"):
mail=smtplib.SMTP('smtp.gmail.com',587)
mail.ehlo()
mail.starttls()
mail.login(user,pwd)
message = 'Subject: {}\n\n{}'.format("ERROR DUPLICATE LONG SIGNAL","ERROR DUPLICATE LONG SIGNAL" )
mail.sendmail(user,"2062348485#mms.att.net",message)
mail.close
else:
if path.exists("Short.txt"):
os.remove("Short.txt")
mail=smtplib.SMTP('smtp.gmail.com',587)
mail.ehlo()
mail.starttls()
mail.login(user,pwd)
message = 'Subject: {}\n\n{}'.format("Close Long Position","Close Long Position" )
mail.sendmail(user,"2062348485#mms.att.net",message)
mail.close
else:
if path.exists("TwoWhite.txt"):
if path.exists("NineWhite.txt"):
open("Long.txt","w+")
mail=smtplib.SMTP('smtp.gmail.com',587)
mail.ehlo()
mail.starttls()
mail.login(user,pwd)
message = 'Subject: {}\n\n{}'.format("BUY NOW!", "BUY NOW!")
mail.sendmail(user,"2062348485#mms.att.net",message)
mail.close
else:
print("No Correlation")
else:
print("No Correlation")
if short != no:
if path.exists("Short.txt"):
mail=smtplib.SMTP('smtp.gmail.com',587)
mail.ehlo()
mail.starttls()
mail.login(user,pwd)
message = 'Subject: {}\n\n{}'.format("ERROR DUPLICATE SHORT SIGNAL","ERROR DUPLICATE SHORT SIGNAL" )
mail.sendmail(user,"2062348485#mms.att.net",message)
mail.close
else:
if path.exists("Long.txt"):
os.remove("Long.txt")
mail=smtplib.SMTP('smtp.gmail.com',587)
mail.ehlo()
mail.starttls()
mail.login(user,pwd)
message = 'Subject: {}\n\n{}'.format("Close Long Position","Close Long Position" )
mail.sendmail(user,"2062348485#mms.att.net",message)
mail.close
else:
if path.exists("TwoBlack.txt"):
if path.exists("NineBlack.txt"):
open("Short.txt","w+")
mail=smtplib.SMTP('smtp.gmail.com',587)
mail.ehlo()
mail.starttls()
mail.login(user,pwd)
message = 'Subject: {}\n\n{}'.format("SELL NOW!", "SELL NOW!")
mail.sendmail(user,"2062348485#mms.att.net",message)
mail.close
else:
print("No Correlation")
else:
print("No Correlation")
if TwoRiskOff !=no:
try:
if path.exists("TwoBlack.txt"):
os.remove("TwoBlack.txt")
if path.exists("TwoWhite.txt"):
os.remove("TwoWhite.txt")
except:
print("Error While Running Two Risk Off")
if NineRiskOff !=no:
try:
if path.exists("NineBlack.txt"):
os.remove("NineBlack.txt")
if path.exists("NineWhite.txt"):
os.remove("NineWhite.txt")
except:
print("Error While Running Two White")
if TwoWhite !=no:
try:
open("TwoWhite.txt","w+")
if path.exists("TwoBlack.txt"):
os.remove("TwoBlack.txt")
except:
print("Error While running Two White")
if TwoBlack !=no:
try:
open("TwoBlack.txt","w+")
if path.exists("TwoWhite.txt"):
os.remove("TwoWhite.txt")
except:
print("Error While running Two Black")
if NineWhite !=no:
try:
open("NineWhite.txt","w+")
if path.exists("NineBlack.txt"):
os.remove("NineBlack.txt")
except:
print("Error While running Nine White")
if NineBlack !=no:
try:
open("NineBlack.txt","w+")
if path.exists("NineWhite.txt"):
os.remove("NineWhite.txt")
except:
print("Error While running Nine Black")
deleteEmail(user,pwd,con)
exit()
I talked to a friend of mine today and he instructed me to run the python file via Powershell and it is working perfectly so far.

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.

Categories