Skip to content

Commit

Permalink
Merge pull request #23 from ghasemnaddaf/fwd_zoom
Browse files Browse the repository at this point in the history
Example usage: forward zoom recording link to a mailing list
  • Loading branch information
awangga authored Feb 24, 2020
2 parents c8ad12c + 51e5b01 commit c66a89c
Show file tree
Hide file tree
Showing 3 changed files with 227 additions and 42 deletions.
65 changes: 55 additions & 10 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,16 +1,16 @@
# Python Outlook(Microsoft email service) Library
# Python Outlook (Microsoft email service) Library
Python Library to read email from live, hotmail, outlook or any microsoft email service, just dowload to yout python script folder. This library using Imaplib python to read email with IMAP protocol.
## Prerequisite Library
Please make sure you have this library installed on your system first before your running this code
## Prerequisite Libraries
Please make sure you have these libraries installed on your system first before running this code:
* email
* imaplib
* smtplib
* datetime

then rename config.py.sample to config.py and edit comment in config.py file

## Example
### To get latest Unread Message in inbox :
## Examples
### To get latest Unread Message in inbox:
```py
import outlook
mail = outlook.Outlook()
Expand All @@ -19,7 +19,7 @@ mail.inbox()
print mail.unread()
```

### To get latest Unread Message in Junk :
### To get latest Unread Message in Junk:
```py
import outlook
mail = outlook.Outlook()
Expand All @@ -28,29 +28,31 @@ mail.junk()
print mail.unread()
```

### Retrive email element :
Use `mail.select(folder)` to switch to folders other than `inbox, `junk`.
### Retrive email element:
```py
print mail.mailbody()
print mail.mailsubject()
print mail.mailfrom()
print mail.mailto()
```

### To send Message :
### To send Message:
```py
import outlook
mail = outlook.Outlook()
mail.login('emailaccount@live.com','yourpassword')
mail.sendEmail('recipient@email.com','subject','message body')
```

### To check Credentials :
### To check Credentials:
```py
import outlook
mail = outlook.Outlook()
mail.checkLogin()
```
### Reading e-mails from Outlook with Python through MAPI and get email with word 'skype id'

### Reading e-mails from Outlook with Python through MAPI and get email with word 'skype id':
```py
import Skype4Py
import outlook
Expand Down Expand Up @@ -111,3 +113,46 @@ while True:
checkingFolder('Junk')

```

### Forward zoom recording email to recipients a mailing list:
Use `fwd_zoom.py`. The class `OutlookMailForwarder` defined there has the capability to filter messages based on the
received time (a time window from now -- in hours), and to do string search in email subject and body. Additionaly,
a filter can be defined to change the body before sending the email. For example, in `fwd_zoom.py`:

```py
def filter_zoom_mailbody(mailbody):
''' Returns the link to share. This filters out other info in the email such as the host-only link'''
m = re.search(r'Share recording with viewers:<br>\s*(.*)\b', mailbody)
return m.group(1)
```

To run, you can either define your `email[space]password` in `.cred` or giveemail/password in stdin upon prompt.
NOTE: Do not forget to `chmod 400 ./.cred` if the former method is used.

Example 1: With existing `.cred` with contents `test@example.com mypassword` and a small time window:
```
./fwd_zoom.py
How many hours to llok back?1
(' > Signed in as test@example.com', ['LOGIN completed.'])
looking up pattern in 3/3 most recent emails in folder zoom
1 items match subject_pattern
1 items match subject_pattern and body_pattern
skipping email_id 213 because its timedelta 6:31:25.556269 is greater than 1 hours
```

Example 2: without a `.cred` file and a large-enough time window:
```
./fwd_zoom.py
Outlook email:test@example.com
Outlook Password:
How many hours to look back?10
(' > Signed in as test@example.com', ['LOGIN completed.'])
looking up pattern in 3/3 most recent emails in folder zoom
1 items match subject_pattern
1 items match subject_pattern and body_pattern
email_id 213 is within range (6:45:22.572372 < 10:00:00)
maillsubject to send: Cloud Recording - Zoom Meeting is now available Tue, 12 Nov 2019 16:51:48 +0000
mailbody to send: https://test.zoom.us/recording/share/4abdcsefkHergre45grdgDdafdefMWd
Sending email...
email sent.
```
117 changes: 117 additions & 0 deletions fwd_zoom.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,117 @@
#!/usr/bin/env python2

import re
import getpass
import outlook
import datetime
from pytz import timezone


class OutlookMailForwarder:
def __init__(self, email_addr, email_passwd, window_hours=24, folder_list=None,
mailing_list=None, subject_pattern='', body_pattern='', filter_body=None):
self.mail = outlook.Outlook()
self.mail.login(email_addr, email_passwd)
self.window_hours = window_hours
self.window_days = (self.window_hours + self.window_hours % 24) / 24
self.folder_list = folder_list
self.mailing_list = mailing_list
self.subject_pattern = subject_pattern
self.body_pattern = body_pattern
self.filter_body = filter_body

def send_email(self, mailsubject, mailbody):
if self.mailing_list is None:
return

if mailsubject is None:
return

for recipient in self.mailing_list:
try:
self.mail.sendEmail(recipient, mailsubject, mailbody)
print('sent mail to %s' % recipient)
except Exception as err:
print('error sending mail to %s: %s' % (recipient, str(err)))

def prepare_email(self, email_id):
self.mail.getEmail(email_id)
mailsubject = self.mail.mailsubject()
maildate = self.mail.maildate()
# filter out any date below now - window_hour
# because outlook searche is limited to the beginning of the day of the now - window_days
maildatetime = datetime.datetime.strptime(maildate[:-6], '%a, %d %b %Y %H:%M:%S')
maildatetime.replace(tzinfo=timezone('UTC'))
timedelta = datetime.datetime.utcnow() - maildatetime
if timedelta > datetime.timedelta(0, 0, 0, 0, 0, self.window_hours):
raise ValueError('skipping email_id %s because its timedelta %s is greater than %d hours' %
(email_id, str(timedelta), self.window_hours))
else:
print('email_id %s is within range (%s < %s)' % (email_id, str(timedelta),
str(datetime.timedelta(0, 0, 0, 0, 0,
self.window_hours))))
mailsubject = mailsubject + ' ' + self.mail.maildate()
mailbody = self.mail.mailbody()
if self.filter_body is not None:
mailbody = self.filter_body(mailbody)
print('maillsubject to send: %s' % mailsubject)
print('mailbody to send: %s' % mailbody)
return (mailsubject, mailbody)

def lookup_pattern(self):
if self.folder_list is None:
return

for folder in self.folder_list:
try:
self.mail.select(folder)
all_ids = self.mail.allIdsSince(self.window_days)
max_num = 100 if len(all_ids) > 100 else len(all_ids)
print('looking up pattern in %d/%d most recent emails in folder %s' % (max_num, len(all_ids), folder))
emails_with_subject_pattern = self.mail.getIdswithWord(all_ids[:max_num], self.subject_pattern)
print('%d items match subject_pattern' % len(emails_with_subject_pattern))
emails_match = self.mail.getIdswithWord(emails_with_subject_pattern, self.body_pattern)
print('%d items match subject_pattern and body_pattern' % len(emails_match))
except Exception as err:
print('error looking up pattern in folder %s: %s' % (folder, str(err)))
continue

try:
for email_id in emails_match:
try:
(mailsubject, mailbody) = self.prepare_email(email_id)
self.send_email(mailsubject, mailbody)
except ValueError as err:
print('%s' % str(err))
continue
except Exception as err:
print('error processing matched emails in folder %s: %s' % (folder, str(err)))
continue


def filter_zoom_mailbody(mailbody):
''' Returns the link to share. This filters out other info in the email such as the host-only link'''
m = re.search(r'Share recording with viewers:<br>\s*(.*)\b', mailbody)
return m.group(1)


def main(_user, _pass, win_hours):
zoom_forwarder = OutlookMailForwarder(_user, _pass, win_hours, folder_list=['zoom'],
mailing_list=['test@example.com'],
subject_pattern='cloud recording',
body_pattern='share recording with viewers:',
filter_body=filter_zoom_mailbody)
zoom_forwarder.lookup_pattern()


if __name__ == '__main__':
try:
with open('.cred', 'r') as f:
userpass = f.readline()
(_user, _pass) = userpass.split()
except IOError:
_user = raw_input('Outlook email:')
_pass = getpass.getpass('Outlook Password:')

win_hours = int(raw_input('How many hours to look back?'))
main(_user, _pass, win_hours)
87 changes: 55 additions & 32 deletions outlook.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,25 +9,27 @@

class Outlook():
def __init__(self):
mydate = datetime.datetime.now()-datetime.timedelta(1)
self.today = mydate.strftime("%d-%b-%Y")
pass
# self.imap = imaplib.IMAP4_SSL('imap-mail.outlook.com')
# self.smtp = smtplib.SMTP('smtp-mail.outlook.com')

def login(self, username, password):
self.username = username
self.password = password
login_attempts = 0
while True:
try:
self.imap = imaplib.IMAP4_SSL(config.imap_server,config.imap_port)
r, d = self.imap.login(username, password)
assert r == 'OK', 'login failed'
print(" > Sign as ", d)
except:
print(" > Sign In ...")
continue
# self.imap.logout()
break
assert r == 'OK', 'login failed: %s' % str (r)
print(" > Signed in as %s" % self.username, d)
return
except Exception as err:
print(" > Sign in error: %s" % str(err))
login_attempts = login_attempts + 1
if login_attempts < 3:
continue
assert False, 'login failed'

def sendEmailMIME(self, recipient, subject, message):
msg = email.mime.multipart.MIMEMultipart()
Expand Down Expand Up @@ -56,18 +58,22 @@ def sendEmail(self, recipient, subject, message):
"content-type: text/html"
])
content = headers + "\r\n\r\n" + message
attempts = 0
while True:
try:
self.smtp = smtplib.SMTP(config.smtp_server, config.smtp_port)
self.smtp.ehlo()
self.smtp.starttls()
self.smtp.login(self.username, self.password)
self.smtp.sendmail(self.username, recipient, content)
print(" email replied")
except:
print(" Sending email...")
continue
break
print(" email sent.")
return
except Exception as err:
print(" Sending email failed: %s" % str(err))
attempts = attempts + 1
if attempts < 3:
continue
raise Exception("Send failed. Check the recipient email address")

def list(self):
# self.login()
Expand All @@ -85,37 +91,34 @@ def junk(self):
def logout(self):
return self.imap.logout()

def today(self):
mydate = datetime.datetime.now()
def since_date(self, days):
mydate = datetime.datetime.now() - datetime.timedelta(days=days)
return mydate.strftime("%d-%b-%Y")

def unreadIdsToday(self):
r, d = self.imap.search(None, '(SINCE "'+self.today+'")', 'UNSEEN')
def allIdsSince(self, days):
r, d = self.imap.search(None, '(SINCE "'+self.since_date(days)+'")', 'ALL')
list = d[0].split(' ')
return list

def getIdswithWord(self, ids, word):
stack = []
for id in ids:
self.getEmail(id)
if word in self.mailbody().lower():
stack.append(id)
return stack
def allIdsToday(self):
return self.allIdsSince(1)

def unreadIds(self):
r, d = self.imap.search(None, "UNSEEN")
def readIdsSince(self, days):
r, d = self.imap.search(None, '(SINCE "'+self.date_since(days)+'")', 'SEEN')
list = d[0].split(' ')
return list

def hasUnread(self):
list = self.unreadIds()
return list != ['']

def readIdsToday(self):
r, d = self.imap.search(None, '(SINCE "'+self.today+'")', 'SEEN')
return self.readIdsSince(1)

def unreadIdsSince(self, days):
r, d = self.imap.search(None, '(SINCE "'+self.since_date(days)+'")', 'UNSEEN')
list = d[0].split(' ')
return list

def unreadIdsToday(self):
return self.unreadIdsSince(1)

def allIds(self):
r, d = self.imap.search(None, "ALL")
list = d[0].split(' ')
Expand All @@ -126,6 +129,23 @@ def readIds(self):
list = d[0].split(' ')
return list

def unreadIds(self):
r, d = self.imap.search(None, "UNSEEN")
list = d[0].split(' ')
return list

def hasUnread(self):
list = self.unreadIds()
return list != ['']

def getIdswithWord(self, ids, word):
stack = []
for id in ids:
self.getEmail(id)
if word in self.mailbody().lower():
stack.append(id)
return stack

def getEmail(self, id):
r, d = self.imap.fetch(id, "(RFC822)")
self.raw_email = d[0][1]
Expand Down Expand Up @@ -192,6 +212,9 @@ def mailfrom(self):
def mailto(self):
return self.email_message['to']

def maildate(self):
return self.email_message['date']

def mailreturnpath(self):
return self.email_message['Return-Path']

Expand Down

0 comments on commit c66a89c

Please sign in to comment.