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
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.
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.