Getting a link from emails using a dedicated account - python

I've been writing automated tests for a web application and it involves sending emails not just for account creation and password resets, but as the premise for the actual product it sends emails with virtual documents.
As part of my tests I obviously need to check that these emails contain certain elements eg. link to sign up, link to documents etc.
I have written some python code (for the gmail atom feed) that would just find and print the title of each email and if their is a link print that too but it cannot find the link.
import urllib2
import untangle
FEED_URL = 'https://mail.google.com/mail/feed/atom'
def get_unread_msgs(user, passwd):
auth_handler = urllib2.HTTPBasicAuthHandler()
auth_handler.add_password(
realm='New mail feed',
uri='https://mail.google.com',
user='{user}#gmail.com'.format(user=user),
passwd=passwd
)
opener = urllib2.build_opener(auth_handler)
urllib2.install_opener(opener)
feed = urllib2.urlopen(FEED_URL)
return feed.read()
if __name__ == "__main__":
import getpass
user = raw_input('Username: ')
passwd = getpass.getpass('Password: ')
xml = get_unread_msgs(user, passwd)
o = untangle.parse(xml)
try:
for item in o.feed.entry:
title = item.title.cdata
print title
link = item.link.cdata
if link:
print "Link"
print ' ', link
except IndexError:
pass # no new mail
Edit: I've just realised that the atom feed doesn't actually give the message data..
Could anyone please suggest an alternative method of achieving my goal?

You could access the messages via imaplib instead:
import imaplib
def get_unread_msgs(user, passwd):
M = imaplib.IMAP4_SSL('imap.gmail.com')
M.login(user, passwd)
try:
M.select()
try:
type, data = M.search(None, '(UNSEEN)')
for num in data[0].split():
yield M.fetch(num, '(RFC822)')
finally:
M.close()
finally:
M.logout()
You will need to enable IMAP in your gmail settings if you haven't already:
Get started with IMAP and POP3

If you are looking for a (gmail specific) solution without polling the server for updates, you can look into the Gmail Notifications API.

Related

imaplib.error: b'LOGIN failed' when trying to login using imaplib

I got that error, credentials is ok and was working in the morning. Reset password did not change,
logging into OWA works fine, login using imaplib fails with "LOGIN failed" after 1 minute or so!
def get_otp():
# sleeping for 20 seconds
time.sleep(20)
# username for mail id
user = '***********'
# password for email id
password = '********'
# hostname for webmail.recogx.ai
hostname = 'mail.office365.com'
print("entered hostname ")
def get_body(msg):
# id=f message is present in more than one part
if msg.is_multipart():
return get_body(msg.get_payload(0))
else:
return msg.get_payload(None, True)
print("bodyyyyyy")
# entering hostname to enter into session
# time.sleep(10)
mail = imaplib.IMAP4_SSL(hostname)
time.sleep(5)
print("logged ")
# logging in page
print("mail login",mail.login(user, password))
mail.login(user, password)
print("logged in")
# selecting inbox
mail.select('INBOX')
# searching unseen messages
result, data = mail.search(None, 'UNSEEN')
# finding total mail numbers
mail_ids = data[0]
id_list = mail_ids.split()
latest = id_list[-1]
print("opt next")
# fetching data from latest email
result, data = mail.fetch(latest, '(RFC822)')
ror = email.message_from_bytes(data[0][1])
body = get_body(ror)
# converting text body from byte to string
body = body.decode("utf-8")
time.sleep(3)
otp = re.search(r'\d{7}', body).group()
Unable to read the OTP.
Microsoft has disabled basic authentication in Office 365:
https://techcommunity.microsoft.com/t5/exchange-team-blog/basic-authentication-deprecation-in-exchange-online-september/ba-p/3609437
However, there might be a method to authenticate using oauth2.
I'm personally working on a solution that might be using:
Office 365 IMAP authentication via OAuth2 and python MSAL library

Reading Gmail Email in Python

I am attempting to create a simple script to check my Gmail for emails with a certain title. When I run this program on Python 3.7.3 I receive this data: ('OK', [b'17']).
I need to access the body of the email within python. I am just not sure what to do with the data that I have.
Here is my current code:
import imaplib
import credentials
imap_ssl_host = 'imap.gmail.com'
imap_ssl_port = 993
username = credentials.email
password = credentials.passwd
server = imaplib.IMAP4_SSL(imap_ssl_host, imap_ssl_port)
server.login(username, password)
server.select('INBOX')
data = server.uid('search',None, '(SUBJECT "MY QUERY HERE!")')
print(data)
The result from running the code:
('OK', [b'17'])
I know it is a little rough, but I am still learning, so any advice you have to help me improve would be greatly appreciated!
You need to first list the contents of the selected mailbox and fetch one of the items. You could do something like this (also check the link suggested by #asynts)
imap.select('Inbox')
status, data = imap.search(None, 'ALL')
for num in data[0].split():
status, data = imap.fetch(num, '(RFC822)')
email_msg = data[0][1]
If you only want specific fields in the body, instead of parsing the RFC you could filter fields like:
status, data = imap.fetch(num, '(BODY[HEADER.FIELDS (SUBJECT DATE FROM TO)])')

Decoding message headers and bodies in python

I'm trying to program a simple mail client in Python which can both send and read messages from inbox in gmail. The sending part works well, but the reading part keeps giving me a bad result.
Here is the python code:
import imaplib
import base64
email_user = '<gmail_address>'
email_pass = '<password>'
M = imaplib.IMAP4_SSL('imap.gmail.com', 993)
M.login(email_user, email_pass)
M.select('inbox')
typ, message_numbers = M.search(None, 'ALL') # change variable name, and use new name in for loop
typ, data = M.fetch(b'1', '(RFC822)')
data1 = base64.b64decode(data[0][1])
print('Message \n%s' %data1)
M.close()
M.logout()
and the result is:
Message
b'\r\xe9b\xbd\xea\xdeu:1\xcaf\xa2\x97M;\x82f\xa2\x95\xca&E\xe7\x1e\x8a\xf7\x9do-\xb4\xd3f\xb5\xef\xdd\x1a\xd7Nt\xd3M4\xc2+aH\xc4\xcf\x89\xdc\xb5\xea\xfe\x9c\xb2\x9d\xb8\xd3\xae\xbd\xf2\x98\xdd2\x89\xf5\xd4W\x9b\xdbM}\xd3nv\xd7\x9d<\xd3C\xd2Mt^q\xe8\xafy\xd6\xf2\xdbM6i\xd7\xfc\xdbgp\x8a\xd8R13\xe2w\x8d\xa6\xaf^\xbb\xefo{\xf3\n\xdb\xeb}y\xe3\xdf<\xdb}\xf9\xdfM\x8c\xa2}u\x15\xe6\xf6\xd3_t\xdb\x9d\xb5\xe7O4\xd0\xf4\x93\x01\x10\x92y\xa9b\xd5\xaa\xecj\xc8Z\xdb\x9e\xad\xd7\x9e=\xf3\xcd\xb7\xdf\x97/\x9e\x89\xdev\n(\x82W\x9c\xa2k'
I appreciate any modified code and hint. Also I'm new to python so please keep your descriptions as simple as possible...
The message you receive in data[0][1] is not base64.
You want to do something like
from email import message_from_bytes
...
msg = message_from_bytes(data[0][1])
and then manipulate msg.

Receive replies from Gmail with smtplib - Python

Ok, I am working on a type of system so that I can start operations on my computer with sms messages. I can get it to send the initial message:
import smtplib
fromAdd = 'GmailFrom'
toAdd = 'SMSTo'
msg = 'Options \nH - Help \nT - Terminal'
username = 'GMail'
password = 'Pass'
server = smtplib.SMTP('smtp.gmail.com:587')
server.starttls()
server.login(username , password)
server.sendmail(fromAdd , toAdd , msg)
server.quit()
I just need to know how to wait for the reply or pull the reply from Gmail itself, then store it in a variable for later functions.
Instead of SMTP which is used for sending emails, you should use either POP3 or IMAP (the latter is preferable).
Example of using SMTP (the code is not mine, see the url below for more info):
import imaplib
mail = imaplib.IMAP4_SSL('imap.gmail.com')
mail.login('myusername#gmail.com', 'mypassword')
mail.list()
# Out: list of "folders" aka labels in gmail.
mail.select("inbox") # connect to inbox.
result, data = mail.search(None, "ALL")
ids = data[0] # data is a list.
id_list = ids.split() # ids is a space separated string
latest_email_id = id_list[-1] # get the latest
result, data = mail.fetch(latest_email_id, "(RFC822)") # fetch the email body (RFC822) for the given ID
raw_email = data[0][1] # here's the body, which is raw text of the whole email
# including headers and alternate payloads
Shamelessly stolen from here
Uku's answer looks reasonable. However, as a pragmatist, I'm going to answer a question you didn't ask, and suggest a nicer IMAP and SMTP library.
I haven't used these myself in anything other then side projects so you'll need to do your own evaluation, but both are much nicer to use.
IMAP
https://github.com/martinrusev/imbox
SMTP:
http://tomekwojcik.github.io/envelopes/
I can suggest you to use this new lib https://github.com/charlierguo/gmail
A Pythonic interface to Google's GMail, with all the tools you'll
need. Search, read and send multipart emails, archive, mark as
read/unread, delete emails, and manage labels.
Usage
from gmail import Gmail
g = Gmail()
g.login(username, password)
#get all emails
mails = g.inbox().mail()
# or if you just want your unread mails
mails = g.inbox().mail(unread=True, from="youradress#gmail.com")
g.logout()

How to auto log into gmail atom feed with Python?

Gmail has this sweet thing going on to get an atom feed:
def gmail_url(user, pwd):
return "https://"+str(user)+":"+str(pwd)+"#gmail.google.com/gmail/feed/atom"
Now when you do this in a browser, it authenticates and forwards you. But in Python, at least what I'm trying, isn't working right.
url = gmail_url(settings.USER, settings.PASS)
print url
opener = urllib.FancyURLopener()
f = opener.open(url)
print f.read()
Instead of forwarding correctly, it's doing this:
>>>
https://user:pass#gmail.google.com/gmail/feed/atom
Enter username for New mail feed at mail.google.com:
This is BAD! I shouldn't have to type in the username and password again!! How can I make it just auto-forward in python as it does in my web browser, so I can get the feed contents without all the BS?
You can use the HTTPBasicAuthHandler, I tried the following and it worked:
import urllib2
def get_unread_msgs(user, passwd):
auth_handler = urllib2.HTTPBasicAuthHandler()
auth_handler.add_password(
realm='New mail feed',
uri='https://mail.google.com',
user='%s#gmail.com' % user,
passwd=passwd
)
opener = urllib2.build_opener(auth_handler)
urllib2.install_opener(opener)
feed = urllib2.urlopen('https://mail.google.com/mail/feed/atom')
return feed.read()

Categories

Resources