Run python script at reception of email - python

I own a shared hosting which can run anacrontab. I would like to run a python script when I receive an email on that server.
Is anacrontab enough?
Or would using a client such as Gmail be better?

import imapclient, pyzmail, html2text
def latestMail():
imapObj = imapclient.IMAPClient('imap.yourServer.com', ssl=False)
imapObj.login('imapUser', 'imapPass')
imapObj.select_folder('Inbox', readonly=False)
UIDs = imapObj.search(criteria='ALL', charset=None)
rawMessages = imapObj.fetch(UIDs[0], ['BODY[]', 'FLAGS'])
message = pyzmail.PyzMessage.factory(rawMessages[UIDs[0]]['BODY[]'])
return message
def parser(message):
if message.text_part is not None and message.html_part is not None:
multipart = True
else:
multipart = False
if message.text_part is not None:
try:
body = message.text_part.get_payload().decode(message.text_part.charset)
except TypeError:
body = message.text_part.get_payload()
if message.html_part is not None and multipart is False:
try:
body = html2text.html2text(message.html_part.get_payload().decode(message.html_part.charset))
except Exception:
raise Systemexit
return body
try:
message = latestMail()
clean = parser(message)
print clean
except IndexError:
print "No messages left"
raise os._exit(0)
except Exception as e:
print e
Crontab config:
HOME=/var/www/html/whatever
* * * * * root /var/www/html/whatever/myMailChecker.py
Conclusion:
This will call your imap servers' Inbox every minute and parse trough your mail and parse it's content, you can do whatever you want after like create a new entry in your mysql table with the mail content etc.. or run another script if clean is not None etc.

Related

Gmail API throws error while sending email, but still sends email

I create an email with the following.
def createGmailEmailNoAttachments(self, messageBody, subject, toEmail, fromEmail, html=False):
try:
newMessage = MIMEMultipart()
newMessage['to']=toEmail
newMessage['from'] = fromEmail
newMessage['subject'] = subject
if html:
msg= MIMEText(messageBody, 'html')
else:
msg= MIMEText(messageBody)
newMessage.attach(msg)
raw = base64.urlsafe_b64encode(newMessage.as_bytes())
raw = raw.decode()
body = {'raw': raw}
return body
except:
self.GLogger.error("An error was encountered while attempting to create gmail email")
tb = traceback.format_exc()
self.GLogger.exception(tb)
return False
I send an email with the following.
def gmailAPISendEmail(self, message, userID="me"):
try:
service = self.gmailAPIService
self.GLogger.info("Attempting to send email message")
request = service.users().messages().send(userId=userID, body=message)
response = self.executeGmailAPI_withretry(request)
if response is False:
return False
responseID = str(response['id'])
self.GLogger.info("Successfully sent email message with ID (" + responseID +")")
return responseID
except:
self.GLogger.error("Failed to send email message")
tb = traceback.format_exc()
self.GLogger.exception(tb)
return False
Where I execute the request in the function executeGmailAPI_withretry(request)
def executeGmailAPI_withretry(self, request, withHTTPObject = False):
try:
response_valid = False
num_retries = 0
while num_retries < 30:
try:
if withHTTPObject is True:
response = request.execute(http=self.http_toUse)
else:
response = request.execute()
response_valid = True
break
except socket.timeout:
num_retries = num_retries + 1
time.sleep(0.5*num_retries)
except:
self.GLogger.error("An error was encounrtered in executeGmailAPI_withretry")
try:
self.GLogger.error(f"The Method ID : {request.methodId}")
except:
pass
try:
self.GLogger.error(f"The uri : {request.uri}")
except:
pass
tb = traceback.format_exc()
self.GLogger.exception(tb)
num_retries = num_retries + 1
time.sleep(0.5*num_retries)
if response_valid is False:
self.GLogger.error(f"Could not resolve issue in 15 requests [{request}]")
return False
else:
return response
except:
self.GLogger.error("An error was encounrtered in executeGmailAPI_withretry")
tb = traceback.format_exc()
self.GLogger.exception(tb)
return False
The problem that I am encountering is as follows. Sometimes, when I want to send an email with these three functions, socket.timeout errors occur during execution of service.users().messages().send(userId=userID, body=message). My retry function will try to send it up to 30 times with some time delays in between. However, sometimes, when a socket.timeout error occurs, the email is still sent. This can result in several of the same emails being sent. From the code's perspective, only one email was sent, since service.users().messages().send(userId=userID, body=message) ran only once successfully without throwing an error.
So, for example, I had 4 identical emails being received, meaning that at least 3 send attempts had a socket.timeout errors in which Gmail actually did send the email and the 4th (or more) attempt executed without throwing the socket.timeout error.
Why does the Gmail API throw a socket.timeout error while sending an email, but still continue to send the email?
This creates a dilemma in the current situation.
If I handle the errors, then it ensures that emails that truly cannot be sent on the first try will be sent. However, it can result in multiple identical emails being sent, due to the false errors.
If I don't handle the error, then for certain, only one email at most will be sent. However, if the email truly cannot be sent, then it will certainly not be sent.
The ideal solution is that the Gmail API should only throw an error if the email truly cannot be sent.
You might want to try setting longer timeout for it to be in timeout mode. See socket.setdefaulttimeout(timeout).
This will force the script to wait until the specified timeout before raising a timeout exception. This way, you might be able to prevent premature timeout exceptions.
If it still doesn't work, maybe you could file it as a bug on issue tracker.
Reference:
socket.timeout with will cause api client to become unuseable
Socket Timeouts

How to delete email from gmail using python IMAP?

I am trying to read otp from mail and after that I want to delete that email from gmail option. I have no problem in reading email but I am not able to delete mail. I tried some code from stackoverflow. below is my code.
def getOtpMail(vEmail, vPaasword):
connection = imaplib.IMAP4_SSL(IMAP_URL) # stablish connection with IMAP server
try:
connection.login(vEmail, vPaasword) # Login with userid password
except Exception as e:
print(e)
return
loopLock = True
while loopLock:
# fetch
connection.select('"INBOX"', readonly=True)
retCode, messages = connection.search(None, '(UNSEEN)')
print(messages[0])
latest = int(messages[0].split()[-1])
res, msg = connection.fetch(str(latest), "(RFC822)")
for response in msg:
if isinstance(response, tuple):
print('\n------------email--------------\n')
msg = email.message_from_bytes(response[1])
if SENDER_NAME in msg['From'] and KEYWORD in msg['Subject']:
loopLock = False
# fetch required information
for part in msg.walk():
body = part.get_payload()
word_list = body.split()
index = word_list.index('verification')
otp = word_list[index + 3].strip('.')
#delete mail - below two line not working
connection.store(str(latest), '+FLAGS', '"[Gmail]/Trash"')
print(connection.expunge())
return otp
else:
continue
I read documentation and print connection.expunge() so I got response as ('NO', [b'EXPUNGE attempt on READ-ONLY folder (Failure)']) . I think issue I have to establish connection in WRITE mode. I am not sure about it.
In this issue, I opened mail box in readonly mode. Hence my program not able to write and store in IMAP server.
I changed
connection.select('"INBOX"', readonly=True)
to
connection.select('"INBOX"', readonly=False)
also I changed command type and flag type in store method -
connection.store(str(latest), '+FLAGS', '"[Gmail]/Trash"')
to
connection.store(str(latest), '+FLAGS', '\\Deleted')
.

How to send notification email when Exception Is Raised?

I have try except block inside for loop. If error happened I want to send an email saying "Error", if not, I need to send an email saying "Success".
code example:
for file in files:
try:
if file.endswith('.csv'):
# converting source variable to str because shutil has some bugs
shutil.move(str(source) + "/" + file, dest_fs01 / current_year_folder / current_year_month_folder)
break
except Exception as e:
error = str(e)
I tried something like this, but if there is no error, the variable error will not be existing
for file in files:
try:
if file.endswith('.csv'):
# converting source variable to str because shutil has some bugs
shutil.move(str(source) + "/" + file, dest_fs01 / current_year_folder / current_year_month_folder)
break
except Exception as e:
error = str(e)
if len(error) > 0:
# sending email notifying about error
message4 = """From: <from#email.com>
To: <to#email.com>
Subject: Error
""" + error
smtpObj.sendmail(sender, receivers, message4)
else:
# sending email notifying about successful completion
message3 = """From: <from#email.com>
To: <to#email.com>
Subject: Success

What can't I parse the API in my Telegram bot code?

I am trying to create a Telegram bot that allows users to search up recipes that require only ingredients that they have on-hand. It is built with Python and I have a rough code, but before I fine-tune the details, I want to get the basic form of it up and running. Unfortunately, I am facing difficulty in parsing the API for the recipes corresponding to ingredients that the user has listed in his/her message. Specifically, the logged error message is "Error parsing the API". Could someone take a look at my code and help me see what went wrong please?
This is the relevant portion of my code:
def handle_messages(messages):
for message in messages:
mappedIngreds = []
for i in range(len(message.text)):
ingred = message.text[i].lower()
if i == 0:
mappedIngreds.append(ingred)
else:
mappedIngreds.append(f"+ {ingred}")
# get responses from API
try:
response = requests.get(f"{apiURL}{mappedIngreds}{apiId}{apiKey}")
response.raise_for_status() # for debugging
except requests.RequestException:
logging.error("Error connecting to the API")
return None
# format responses into list of recipes
try:
recipes = []
for i in response.json():
recipeInfo = {}
recipeInfo["name"] = i["label"]
recipeInfo["url"] = i["url"]
recipes.append(recipeInfo)
except (KeyError, TypeError, ValueError):
logging.error("Error parsing the API")
return None
# send list of recipes to user
try:
bot.reply_to(message.chat.id, "Try these recipes:", *recipeInfo["name"], *recipeInfo["url"], sep="\n")
except:
logging.error("Error printing recipes")
My full code is here: https://pastebin.com/W0CceAt9

How can I retrieve a Google Talk users Status Message

I'd like to be able to retrieve a users Google Talk Status Message with Python, it's really hard to find documentation on how to use some of the libraries out there.
I don't have anything to hand with xmpp installed, but here's some old code I had lying around that might help you. You'll want to update the USERNAME/PASSWORD to your own values for test purposes.
Things to note: users logged in to Google Talk get a random presence string on their userid: that doesn't matter if you are trying to get the status of some other user, but if you want to write some code so want to communicate with yourself you need to distinguish the user logged in from GMail or a GTalk client from the test program. Hence the code searches through the userids.
Also, if you read the status immediately after logging in you probably won't get anything. There's a delay in the code because it takes a little while for the status to become available.
"""Send a single GTalk message to myself"""
import xmpp
import time
_SERVER = 'talk.google.com', 5223
USERNAME = 'someuser#gmail.com'
PASSWORD = 'whatever'
def sendMessage(tojid, text, username=USERNAME, password=PASSWORD):
jid = xmpp.protocol.JID(username)
client = xmpp.Client(jid.getDomain(), debug=[])
#self.client.RegisterHandler('message', self.message_cb)
if not client:
print 'Connection failed!'
return
con = client.connect(server=_SERVER)
print 'connected with', con
auth = client.auth(jid.getNode(), password, 'botty')
if not auth:
print 'Authentication failed!'
return
client.RegisterHandler('message', message_cb)
roster = client.getRoster()
client.sendInitPresence()
if '/' in tojid:
tail = tojid.split('/')[-1]
t = time.time() + 1
while time.time() < t:
client.Process(1)
time.sleep(0.1)
if [ res for res in roster.getResources(tojid) if res.startswith(tail) ]:
break
for res in roster.getResources(tojid):
if res.startswith(tail):
tojid = tojid.split('/', 1)[0] + '/' + res
print "sending to", tojid
id = client.send(xmpp.protocol.Message(tojid, text))
t = time.time() + 1
while time.time() < t:
client.Process(1)
time.sleep(0.1)
print "status", roster.getStatus(tojid)
print "show", roster.getShow(tojid)
print "resources", roster.getResources(tojid)
client.disconnect()
def message_cb(session, message):
print ">", message
sendMessage(USERNAME + '/Talk', "This is an automatically generated gtalk message: did you get it?")

Categories

Resources