Gmail & Outlook Thread Creator
python
30 Aug 2017
This is a demo of email thread generator based from Gmail to Gmail and Outlook. It can
Send N email with different titles.
Create an email thread with N conversations (i.e. grouping N emails
together).
Prerequisite:
Check out Gmail API quickstart to authorize API usage and save the private key file client_secret.json in your working directory.
Syntax:
#create 5 emails all with different title
python sender . py -- to youralias @ gmail . com -- num_threads 5
#create 10 emails in the same thread
python sender . py -- to youralias @ gmail . com -- num_conversations 10
Since Outlook classifies emails a little different, to make the conversational thread work, a user needs to copy to message ID from the first email. Command line message will provide a step by step guide.
# sender.py
import httplib2
import os
import oauth2client
from oauth2client import client , tools
import base64
from email.mime.multipart import MIMEMultipart
from email.mime.text import MIMEText
from apiclient import errors , discovery
SCOPES = 'https://www.googleapis.com/auth/gmail.send'
CLIENT_SECRET_FILE = 'client_secret.json'
APPLICATION_NAME = 'Gmail API Python Send Email'
def get_credentials ():
home_dir = os . path . expanduser ( '~' )
credential_dir = os . path . join ( home_dir , '.credentials' )
if not os . path . exists ( credential_dir ):
os . makedirs ( credential_dir )
credential_path = os . path . join ( credential_dir , 'gmail-python-email-send.json' )
store = oauth2client . file . Storage ( credential_path )
credentials = store . get ()
if not credentials or credentials . invalid :
flow = client . flow_from_clientsecrets ( CLIENT_SECRET_FILE , SCOPES )
flow . user_agent = APPLICATION_NAME
credentials = tools . run_flow ( flow , store )
print ( 'Storing credentials to ' + credential_path )
return credentials
def SendMessage ( sender , to , subject , msgHtml , msgPlain , msgId = '' , threadId = '' ):
credentials = get_credentials ()
http = credentials . authorize ( httplib2 . Http ())
service = discovery . build ( 'gmail' , 'v1' , http = http )
message1 = CreateMessage ( sender , to , subject , msgHtml , msgPlain , msgId , threadId )
return SendMessageInternal ( service , "me" , message1 )
def SendMessageInternal ( service , user_id , message ):
''' if success, return threadID, else return None'''
try :
message = ( service . users (). messages (). send ( userId = user_id , body = message ). execute ())
print ( 'Thread Id: %s' % message [ 'id' ])
return message [ 'id' ]
except errors . HttpError as error :
print ( 'An error occurred: %s' % error )
return None
def CreateMessage ( sender , to , subject , msgHtml , msgPlain , msgId , threadId ):
'''threadId: for gmail; msgId: for Outlook'''
msg = MIMEMultipart ()
msg [ 'Subject' ] = subject
msg [ 'From' ] = sender
msg [ 'To' ] = to
if msgId :
msg [ 'In-Reply-To' ] = msgId
msg [ 'References' ] = msgId
msg . attach ( MIMEText ( msgPlain , 'plain' ))
msg . attach ( MIMEText ( msgHtml , 'html' ))
raw = base64 . urlsafe_b64encode ( msg . as_bytes ())
raw = raw . decode ()
body = { 'raw' : raw }
if threadId :
body [ 'threadId' ] = threadId
return body
def CreateConversations ( sender , to , subject , msgHtml , msgPlain , msgId , threadId , num ):
for i in range ( num ):
# retry until success
success = False
while not success :
success = SendMessage ( sender , to , subject , msgHtml , msgPlain , msgId , threadId )
if __name__ == '__main__' :
import argparse
parser = argparse . ArgumentParser ()
parser . add_argument ( '--to' , type = str , default = 'foobarplay@gmail.com' )
parser . add_argument ( '--title' , type = str , help = 'email title' , default = 'Thread' )
parser . add_argument ( '--num_threads' , type = int , help = 'num_threads' , default = 1 )
parser . add_argument ( '--num_conversations' , type = int , help = 'num conversations of a thread (thread ID required)' , default = 1 )
args = parser . parse_args ()
# create first mail, get msg id
to = args . to
sender = "youralias@gmail.com"
msgHtml , msgPlain = "bar" , "foo"
is_gmail = 'gmail' in args . to
for i in range ( args . num_threads ):
subject = args . title + ( str ( i ) if i > 0 else '' )
# retry until success
Id = None
while not Id :
Id = SendMessage ( sender , to , subject , msgHtml , msgPlain )
threadId , msgId = '' , ''
if args . num_conversations > 1 :
if is_gmail :
threadId = Id
else :
msgId = input ( 'Please check the latest mail and insert its msgId (e.g. <CAFi=xyz@mail.gmail.com>):' )
CreateConversations ( sender , to , subject , msgHtml , msgPlain , msgId , threadId , args . num_conversations - 1 )
print ( 'Conversations created to the given thread' )