meteortools.utils.sendAnEmail

  1# Copyright (C) 2018-2023 Mark McIntyre
  2import os
  3import platform
  4import base64
  5import email
  6from email.mime.text import MIMEText
  7from email.mime.multipart import MIMEMultipart
  8
  9from google.auth.transport.requests import Request
 10from google.oauth2.credentials import Credentials
 11from google_auth_oauthlib.flow import InstalledAppFlow
 12from googleapiclient.discovery import build
 13
 14# If modifying these scopes, delete the file token.json.
 15SCOPES =['https://mail.google.com/']
 16
 17
 18def _getGmailCreds(tokfile=None, crdfile=None):
 19    creds = None
 20    # The file token.json stores the user's access and refresh tokens, and is
 21    # created automatically when the authorization flow completes for the first
 22    # time.
 23    if tokfile is None:
 24        tokfile = '~/.ssh/gmailtoken.json'
 25    if crdfile is None:
 26        crdfile = '~/.ssh/gmailcreds.json'
 27    tokfile = os.path.expanduser(tokfile)
 28    crdfile = os.path.expanduser(crdfile)
 29    if os.path.exists(tokfile):
 30        creds = Credentials.from_authorized_user_file(tokfile, SCOPES)
 31    # If there are no (valid) credentials available, let the user log in.
 32    if not creds or not creds.valid:
 33        if creds and creds.expired and creds.refresh_token:
 34            creds.refresh(Request())
 35        else:
 36            if not os.path.isfile(crdfile):
 37                print(f'to use this function you must have stored your Google OAUTH2 secret json file in {crdfile}')
 38                print('To set up OAUTH2 go to your google cloud console, select APIs then Credentials, and add an OAUTH2 desktop client ID.')
 39                return None
 40            flow = InstalledAppFlow.from_client_secrets_file(crdfile, SCOPES)
 41            creds = flow.run_local_server(port=0)
 42        # Save the credentials for the next run
 43        with open(tokfile, 'w') as token:
 44            token.write(creds.to_json())
 45    return creds
 46
 47
 48def _refreshCreds(tokfile=None, crdfile=None):
 49    creds = None
 50    # The file token.json stores the user's access and refresh tokens, and is
 51    # created automatically when the authorization flow completes for the first
 52    # time.
 53    if tokfile is None:
 54        tokfile = '~/.ssh/gmailtoken.json'
 55    if crdfile is None:
 56        crdfile = '~/.ssh/gmailcreds.json'
 57    tokfile = os.path.expanduser(tokfile)
 58    crdfile = os.path.expanduser(crdfile)
 59    if os.path.exists(tokfile):
 60        creds = Credentials.from_authorized_user_file(tokfile, SCOPES)
 61    # If there are no (valid) credentials available, let the user log in.
 62    if not creds or not creds.valid:
 63        if creds and creds.expired and creds.refresh_token:
 64            try: 
 65                creds.refresh(Request())
 66            except: 
 67                flow = InstalledAppFlow.from_client_secrets_file(crdfile, SCOPES)
 68                creds = flow.run_local_server(port=0)
 69        # Save the credentials for the next run
 70        if creds.valid:
 71            with open(tokfile, 'w') as token:
 72                token.write(creds.to_json())
 73        else:
 74            print('credentials not valid, try again')
 75    return creds
 76
 77
 78def _create_message(sender, to, subject, message_text, msg_text_html=None):
 79    if msg_text_html is None:
 80        msg = MIMEText(message_text)
 81    else:
 82        msg = MIMEMultipart('alternative')
 83        msg.attach(MIMEText(message_text, 'plain'))
 84        msg.attach(MIMEText(msg_text_html, 'html')) # html must be the last part
 85    msg['to'] = to
 86    msg['from'] = sender
 87    msg['subject'] = subject
 88    return {'raw': base64.urlsafe_b64encode(msg.as_string().encode('utf-8')).decode('utf-8')}
 89
 90
 91
 92def sendAnEmail(mailrecip, message, subject, mailfrom, files=None, tokfile=None, crdfile=None, msg_html=None):
 93    """ sends an email using gmail. 
 94    
 95        Arguments:  
 96            mailrecip:  [string] email address of recipient.  
 97            message:    [string] the message to send.  
 98            subject:    [string] Subject line.
 99            mailfrom:   [string] email address of sender.   
100        Keyword Args:
101            files:      [list]   list of files to attach, not currently implemented.  
102            tokfile:    [string] full path to token file, if not ~/.ssh/gmailtoken.json  
103            crdfile:    [string] full path to credentials file, if not ~/.ssh/gmailcreds.json  
104            msg_html:   [string] HTML version of the message body, if any  
105
106        Returns:  
107            Nothing, though a message is printed onscreen.  
108
109        Notes:  
110            You must have gmail OAUTH2 set up. The gmail credentials default to gmailtoken.json and
111            gmailcreds.json in the  $HOME/.ssh folder.  
112        """
113    
114    if subject is None:
115        subject = platform.uname()[1]
116
117    # email a summary to the mailrecip
118    creds = _getGmailCreds(tokfile, crdfile)
119    if not creds:
120        return 
121    service = build('gmail', 'v1', credentials=creds)
122
123    #message = '{:s}: {:s}'.format(msgtype, message)
124
125    subj = subject
126    mailmsg = _create_message(mailfrom, mailrecip, subj, message, msg_text_html=msg_html)
127
128    try:
129        retval = (service.users().messages().send(userId='me', body=mailmsg).execute())
130        print('Message Id: %s' % retval['id'])
131    except:
132        print('An error occurred sending the message')
133
134
135def forwardAnEmail(reciplist, msgid=None, tokfile=None, crdfile=None):
136    """ Forward email from a gmail account to a list of recipients  
137    
138        Arguments:  
139            recplist:   [list of strings] list of addresses to forward to  
140
141        Keyword arguments:  
142            msgid:      [string] gmail message id. If None, then all unread mail is forwarded  
143            tokfile:    [string] full path to a gmail oauth2 json token file  
144            crdfile:    [string] full path to a gmail oauth2 json credentials file for initial authorization 
145
146        To obtain the oauth2 credentials file, go to the google cloud console, select APIs and enable gmail. Then 
147         go to Credentials and create an OAUTH2 Client ID for Desktop and download the JSON credentials file. 
148         Upon first run, you'll be taken to the gmail authorisation screen and the token file will be created. 
149         Subsequent runs will use the token file. The creds file will be used to reauthorise periodically. 
150       """
151    creds = _getGmailCreds(tokfile, crdfile)
152    if not creds:
153        return 
154    service = build('gmail', 'v1', credentials=creds)
155    userid = 'me'
156    if msgid is None:
157        try:
158            msglist = (service.users().messages().list(userId=userid, labelIds=['INBOX','UNREAD']).execute())
159            for msg in msglist['messages']:
160                msgid = msg['id']
161                # retrieve raw mail
162                message = (service.users().messages().get(userId='me', id=msgid, format='raw').execute())
163                # decode it from base64
164                decmsg = base64.urlsafe_b64decode(message['raw'])
165                newmsg = email.message_from_bytes(decmsg)
166                newmsg.add_header('Reply-To',newmsg['from']) 
167                newmsg.replace_header('Subject','Fwd: ' + newmsg['subject'])
168                # Send it
169                for recip in reciplist:
170                    newmsg.replace_header('To', recip)
171                    mailmsg = {'raw': base64.urlsafe_b64encode(newmsg.as_string().encode('utf-8')).decode('utf-8')}
172                    retval = (service.users().messages().send(userId='me', body=mailmsg).execute())
173                    # This will mark the messagea as read
174                    service.users().messages().modify(userId=userid, id=msgid, body={'removeLabelIds': ['UNREAD']}).execute() 
175                    print(retval)
176        except Exception:
177            print('Nothing to forward')
178    else:
179        try:
180            message = (service.users().messages().get(userId='me', id=msgid, format='raw').execute())
181            # decode it from base64
182            decmsg = base64.urlsafe_b64decode(message['raw'])
183            newmsg = email.message_from_bytes(decmsg)
184            newmsg.add_header('Reply-To',newmsg['from']) 
185            newmsg.replace_header('Subject','Fwd: ' + newmsg['subject'])
186            # Send it
187            for recip in reciplist:
188                newmsg.replace_header('To', recip)
189                mailmsg = {'raw': base64.urlsafe_b64encode(newmsg.as_string().encode('utf-8')).decode('utf-8')}
190                retval = (service.users().messages().send(userId='me', body=mailmsg).execute())
191                # This will mark the messagea as read
192                service.users().messages().modify(userId=userid, id=msgid, body={'removeLabelIds': ['UNREAD']}).execute() 
193                print(retval)
194        except Exception:
195            print('Nothing to forward')
196    return 
SCOPES = ['https://mail.google.com/']
def sendAnEmail( mailrecip, message, subject, mailfrom, files=None, tokfile=None, crdfile=None, msg_html=None):
 93def sendAnEmail(mailrecip, message, subject, mailfrom, files=None, tokfile=None, crdfile=None, msg_html=None):
 94    """ sends an email using gmail. 
 95    
 96        Arguments:  
 97            mailrecip:  [string] email address of recipient.  
 98            message:    [string] the message to send.  
 99            subject:    [string] Subject line.
100            mailfrom:   [string] email address of sender.   
101        Keyword Args:
102            files:      [list]   list of files to attach, not currently implemented.  
103            tokfile:    [string] full path to token file, if not ~/.ssh/gmailtoken.json  
104            crdfile:    [string] full path to credentials file, if not ~/.ssh/gmailcreds.json  
105            msg_html:   [string] HTML version of the message body, if any  
106
107        Returns:  
108            Nothing, though a message is printed onscreen.  
109
110        Notes:  
111            You must have gmail OAUTH2 set up. The gmail credentials default to gmailtoken.json and
112            gmailcreds.json in the  $HOME/.ssh folder.  
113        """
114    
115    if subject is None:
116        subject = platform.uname()[1]
117
118    # email a summary to the mailrecip
119    creds = _getGmailCreds(tokfile, crdfile)
120    if not creds:
121        return 
122    service = build('gmail', 'v1', credentials=creds)
123
124    #message = '{:s}: {:s}'.format(msgtype, message)
125
126    subj = subject
127    mailmsg = _create_message(mailfrom, mailrecip, subj, message, msg_text_html=msg_html)
128
129    try:
130        retval = (service.users().messages().send(userId='me', body=mailmsg).execute())
131        print('Message Id: %s' % retval['id'])
132    except:
133        print('An error occurred sending the message')

sends an email using gmail.

Arguments:
mailrecip: [string] email address of recipient.
message: [string] the message to send.
subject: [string] Subject line. mailfrom: [string] email address of sender.
Keyword Args: files: [list] list of files to attach, not currently implemented.
tokfile: [string] full path to token file, if not ~/.ssh/gmailtoken.json
crdfile: [string] full path to credentials file, if not ~/.ssh/gmailcreds.json
msg_html: [string] HTML version of the message body, if any

Returns:
Nothing, though a message is printed onscreen.

Notes:
You must have gmail OAUTH2 set up. The gmail credentials default to gmailtoken.json and gmailcreds.json in the $HOME/.ssh folder.

def forwardAnEmail(reciplist, msgid=None, tokfile=None, crdfile=None):
136def forwardAnEmail(reciplist, msgid=None, tokfile=None, crdfile=None):
137    """ Forward email from a gmail account to a list of recipients  
138    
139        Arguments:  
140            recplist:   [list of strings] list of addresses to forward to  
141
142        Keyword arguments:  
143            msgid:      [string] gmail message id. If None, then all unread mail is forwarded  
144            tokfile:    [string] full path to a gmail oauth2 json token file  
145            crdfile:    [string] full path to a gmail oauth2 json credentials file for initial authorization 
146
147        To obtain the oauth2 credentials file, go to the google cloud console, select APIs and enable gmail. Then 
148         go to Credentials and create an OAUTH2 Client ID for Desktop and download the JSON credentials file. 
149         Upon first run, you'll be taken to the gmail authorisation screen and the token file will be created. 
150         Subsequent runs will use the token file. The creds file will be used to reauthorise periodically. 
151       """
152    creds = _getGmailCreds(tokfile, crdfile)
153    if not creds:
154        return 
155    service = build('gmail', 'v1', credentials=creds)
156    userid = 'me'
157    if msgid is None:
158        try:
159            msglist = (service.users().messages().list(userId=userid, labelIds=['INBOX','UNREAD']).execute())
160            for msg in msglist['messages']:
161                msgid = msg['id']
162                # retrieve raw mail
163                message = (service.users().messages().get(userId='me', id=msgid, format='raw').execute())
164                # decode it from base64
165                decmsg = base64.urlsafe_b64decode(message['raw'])
166                newmsg = email.message_from_bytes(decmsg)
167                newmsg.add_header('Reply-To',newmsg['from']) 
168                newmsg.replace_header('Subject','Fwd: ' + newmsg['subject'])
169                # Send it
170                for recip in reciplist:
171                    newmsg.replace_header('To', recip)
172                    mailmsg = {'raw': base64.urlsafe_b64encode(newmsg.as_string().encode('utf-8')).decode('utf-8')}
173                    retval = (service.users().messages().send(userId='me', body=mailmsg).execute())
174                    # This will mark the messagea as read
175                    service.users().messages().modify(userId=userid, id=msgid, body={'removeLabelIds': ['UNREAD']}).execute() 
176                    print(retval)
177        except Exception:
178            print('Nothing to forward')
179    else:
180        try:
181            message = (service.users().messages().get(userId='me', id=msgid, format='raw').execute())
182            # decode it from base64
183            decmsg = base64.urlsafe_b64decode(message['raw'])
184            newmsg = email.message_from_bytes(decmsg)
185            newmsg.add_header('Reply-To',newmsg['from']) 
186            newmsg.replace_header('Subject','Fwd: ' + newmsg['subject'])
187            # Send it
188            for recip in reciplist:
189                newmsg.replace_header('To', recip)
190                mailmsg = {'raw': base64.urlsafe_b64encode(newmsg.as_string().encode('utf-8')).decode('utf-8')}
191                retval = (service.users().messages().send(userId='me', body=mailmsg).execute())
192                # This will mark the messagea as read
193                service.users().messages().modify(userId=userid, id=msgid, body={'removeLabelIds': ['UNREAD']}).execute() 
194                print(retval)
195        except Exception:
196            print('Nothing to forward')
197    return 

Forward email from a gmail account to a list of recipients

Arguments:
recplist: [list of strings] list of addresses to forward to

Keyword arguments:
msgid: [string] gmail message id. If None, then all unread mail is forwarded
tokfile: [string] full path to a gmail oauth2 json token file
crdfile: [string] full path to a gmail oauth2 json credentials file for initial authorization

To obtain the oauth2 credentials file, go to the google cloud console, select APIs and enable gmail. Then go to Credentials and create an OAUTH2 Client ID for Desktop and download the JSON credentials file. Upon first run, you'll be taken to the gmail authorisation screen and the token file will be created. Subsequent runs will use the token file. The creds file will be used to reauthorise periodically.