def encodedMIMEText(body, encoding=None): """Wrap ``MIMEText`` with ``guess_encoding`` detection. >>> message = encodedMIMEText('Hello') >>> print(message.as_string()) # doctest: +REPORT_UDIFF Content-Type: text/plain; charset="us-ascii" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit Content-Disposition: inline <BLANKLINE> Hello >>> message = encodedMIMEText('Джон Доу') >>> print(message.as_string()) # doctest: +REPORT_UDIFF Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: base64 Content-Disposition: inline <BLANKLINE> 0JTQttC+0L0g0JTQvtGD <BLANKLINE> """ if encoding == None: encoding = guess_encoding(body) if encoding == 'us-ascii': message = _MIMEText(body) else: # Create the message ('plain' stands for Content-Type: text/plain) message = _MIMEText(body, 'plain', encoding) message.add_header('Content-Disposition', 'inline') return message
def _get_mine_message(self): ''' generate MIMEText or MIMEMultipart objects ''' if self._attachments: return _MIMEMultipart('related') elif self.html: #return _MIMEMultipart('alternative') return _MIMEText(self.html, 'html', self.encoding) return _MIMEText(self.text, 'plain', self.encoding)
def _add_plain_multipart(guid: str, message, html: str): headers = message.items() msg = MIMEMultipart('alternative') for name, value in headers: if name.lower().startswith('content-'): continue msg[str(name)] = value html_part = _MIMEText(html, _subtype='html') msg.attach(html_part) text_content = html2text.html2text(html=html, baseurl=guid) text_part = _MIMEText(text_content) msg.attach(text_part) return msg
def _attach_files(self, outer): ''' attach file list ''' for attachment in self._attachments: filename = attachment cid = None if (isinstance(attachment, list) or isinstance(attachment, tuple) and len(attachment) == 2): filename, cid = attachment ctype, encoding = mimetypes.guess_type(filename) if ctype is None or encoding is not None: ctype = 'application/octet-stream' maintype, subtype = ctype.split('/', 1) fp = open(filename, 'rb') if maintype == 'text': msg = _MIMEText(fp.read(), _subtype=subtype) elif maintype == 'image': msg = _MIMEImage(fp.read(), _subtype=subtype) elif maintype == 'audio': msg = _MIMEAudio(fp.read(), _subtype=subtype) else: msg = _MIMEBase(maintype, subtype) msg.set_payload(fp.read()) _encoder.encode_base64(msg) fp.close() if cid: msg.add_header('Content-ID', '<%s>' % cid) msg.add_header('Content-Disposition', 'inline') else: msg.add_header('Content-Disposition', 'attachment', filename=os.path.basename(filename)) outer.attach(msg) return
def text(self, text): ''' .. seealso:: :attr:`text` ''' if text: if not isinstance(text, str): text = _pformat(text) text += '\n\n' self.m('add text to mail', more=dict(len=len(text))) self.__message.attach(_MIMEText(text, 'plain', 'UTF-8'))
def email(to, subject, body): """Sends email, doing all the (not so) heavy lifting.""" try: s = _SMTP('localhost') msg = _MIMEText(body) msg['from'] = 'Driver Mail Subsystem <noreply@%s>' % _getfqdn() msg['to'] = to msg['subject'] = subject s.sendmail(msg['from'], msg['to'], msg.as_string()) s.quit() logger.info('Sent mail to %s with subject %s.', msg['to'], msg['subject']) except Exception as e: logger.exception(e)
def text(self, text): ''' .. seealso:: :attr:`text` ''' if text: if not isinstance(text, str): text = _pformat(text) text += '\n\n' self.m( 'add text to mail', more=dict(len=len(text)) ) self.__message.attach(_MIMEText(text, 'plain', 'UTF-8'))
def myMIMEText(body, subtype=None, encoding='utf-8', filename=None): r"""Wrap ``MIMEText`` with proper ``encoding`` only utf-8 or us-ascii are supported by default: all text files are encoded with utf-8 to avoid signature error if, however, you don't like this, risk yourself for us-ascii/utf-8 """ if ( encoding != 'utf-8' ): if nonAsciiString(body): encoding = 'utf-8' else: encoding = 'us-ascii' message = _MIMEText(body, subtype, encoding) message.add_header('Content-Disposition', 'inline', filename = filename) return message
def get_message(sender, recipient, subject, body, content_type="plain", extra_headers=None): """Generate a `Message` instance. All arguments should be Unicode strings (plain ASCII works as well). Only the real name part of sender and recipient addresses may contain non-ASCII characters. The email will be properly MIME encoded. The charset of the email will be the first one out of the list that can represent all the characters occurring in the email. """ # Split real name (which is optional) and email address parts sender_name, sender_addr = _parseaddr(sender) recipient_name, recipient_addr = _parseaddr(recipient) sender_encoding = guess_encoding(sender_name) recipient_encoding = guess_encoding(recipient_name) subject_encoding = guess_encoding(subject) body_encoding = guess_encoding(body) # We must always pass Unicode strings to Header, otherwise it will # use RFC 2047 encoding even on plain ASCII strings. sender_name = str(_Header(sender_name, sender_encoding).encode()) recipient_name = str(_Header(recipient_name, recipient_encoding).encode()) # Make sure email addresses do not contain non-ASCII characters sender_addr.encode('ascii') recipient_addr.encode('ascii') # Create the message ('plain' stands for Content-Type: text/plain) message = _MIMEText(body, content_type, body_encoding) message['From'] = _formataddr((sender_name, sender_addr)) message['To'] = _formataddr((recipient_name, recipient_addr)) message['Subject'] = _Header(subject, subject_encoding) if extra_headers: for key, value in extra_headers.items(): encoding = guess_encoding(value) message[key] = _Header(value, encoding) return message
def send(self): """Send message """ def do_send(msg: Message): try: engine = _SMTP('localhost') engine.sendmail(msg._from_addr, msg._to_addrs, str(msg)) log_msg = "Message '{}' has been sent to {}.".format(msg.subject, msg.to_addrs) _logger.info(log_msg) except Exception as e: _logger.error('Unable to send message to {}: {}'.format(msg.to_addrs, e), exc_info=e) super().attach(_MIMEText(self.body, 'html', 'utf-8')) for attachment in self._attachments: super().attach(attachment) _threading.run_in_thread(do_send, msg=self) _logger.info('Started new message send thread to {}'.format(self.to_addrs))
def notify(self): config = load_config() assert ( config.get('notify', 'email_address') != 'None' ), 'No email has been specified, _please do so in ~/.ceilopy/config.ini' out = self._last_processing messages = ['run started {}'.format(out['start_time'])] messages.append('run finshed {}'.format(out['finish_time'])) #### summary no_of_errors = len(out['errors']) no_of_files_processed = out['no_of_files_processed'] messages.append('\n'.join([ f'length of workplan:\t\t{self.workplan.shape[0]}', f'successfully created files:\t{no_of_files_processed}', f'errors encountered:\t\t{no_of_errors}' ])) #### errors if no_of_errors != 0: errs = out['errors'] err_types = _np.array([err.__class__.__name__ for err in errs]) typoferrors = [] for toe in _np.unique(err_types): typoferrors.append({ 'name': toe, 'times': (err_types == toe).sum(), 'first_err': errs[_np.where(err_types == toe)[0][0]] }) messages.append('\n'.join([ 'Errors by type:', ] + [ '\t{tn}:\t{tt}'.format(tn=toe['name'], tt=toe['times']) for toe in typoferrors ])) messages.append( '\n=============================================\n'.join([ 'First traceback for each error type', ] + [ ''.join( _tb.format_tb(toe['first_err'].__traceback__) + [ toe['first_err'].__str__(), ]) for toe in typoferrors ])) #### email body message_txt = '\n=========================================================================\n'.join( messages) msg = _MIMEText(message_txt) #### subject if no_of_errors == 0: status = 'clean' else: status = 'errors' subject = f'cl51cloudprod - status: {status} (clean: {no_of_files_processed}; errors: {no_of_errors})' address = config.get('notify', 'email_address') smtp = config.get('notify', 'smtp') msg['Subject'] = subject msg['From'] = address msg['To'] = address # Send the message via our own SMTP server. s = _smtplib.SMTP(smtp) s.send_message(msg) s.quit()
def _attach_text(self, msg, inline=False): ''' attach plain text body ''' part = _MIMEText(self.text, 'plain', self.encoding) if inline: part.add_header('Content-Disposition', 'inline') msg.attach(part)
def _attach_html(self, msg, inline=False): ''' attach html body ''' part = _MIMEText(self.html, 'html', self.encoding) if inline: part.add_header('Content-Disposition', 'inline') msg.attach(part)
f"{index}.pdf") # Set the content of the attachment: ctype, encoding = _mimetypes.guess_type(source_pdf) maintype, subtype = ctype.split('/', 1) with open(source_pdf, 'rb') as fp: msg = _MIMEImage(fp.read(), _subtype=subtype) # Set the filename parameter msg.add_header('Content-Disposition', 'attachment', filename=_settings.EMAIL_PDF) outer.attach(msg) # Add our message: part1 = _MIMEText(body, 'plain', 'UTF-8') outer.attach(part1) # Now send the message try: smtp.sendmail(_settings.SMTP_USER, email, outer.as_bytes()) except _smtplib.SMTPRecipientsRefused: print(f'Cannot send to {email}. Recipient refused.') except Exception as e: print( f'Cannot send to {email} due to server error: {e}') _traceback.print_exc() break else: print(f'Mail sent to {email}')
def get_message(sender, recipient, subject, body, content_type, extra_headers=None, config=None, section='DEFAULT'): """Generate a `Message` instance. All arguments should be Unicode strings (plain ASCII works as well). Only the real name part of sender and recipient addresses may contain non-ASCII characters. The email will be properly MIME encoded. The charset of the email will be the first one out of the list that can represent all the characters occurring in the email. >>> message = get_message( ... sender='John <*****@*****.**>', recipient='Ζεύς <*****@*****.**>', ... subject='Testing', ... body='Hello, world!\\n', ... content_type='plain', ... extra_headers={'Approved': '*****@*****.**'}) >>> print(message.as_string()) # doctest: +REPORT_UDIFF MIME-Version: 1.0 Content-Type: text/plain; charset="us-ascii" Content-Transfer-Encoding: 7bit From: John <*****@*****.**> To: =?utf-8?b?zpbOtc+Nz4I=?= <*****@*****.**> Subject: Testing Approved: [email protected] <BLANKLINE> Hello, world! <BLANKLINE> """ if config is None: config = _config.CONFIG if section not in config.sections(): section = 'DEFAULT' encodings = [ x.strip() for x in config.get(section, 'encodings').split(',')] # Split real name (which is optional) and email address parts sender_name,sender_addr = _parseaddr(sender) recipient_name,recipient_addr = _parseaddr(recipient) sender_encoding = guess_encoding(sender_name, encodings) recipient_encoding = guess_encoding(recipient_name, encodings) subject_encoding = guess_encoding(subject, encodings) body_encoding = guess_encoding(body, encodings) # We must always pass Unicode strings to Header, otherwise it will # use RFC 2047 encoding even on plain ASCII strings. sender_name = str(_Header(sender_name, sender_encoding).encode()) recipient_name = str(_Header(recipient_name, recipient_encoding).encode()) # Make sure email addresses do not contain non-ASCII characters sender_addr.encode('ascii') recipient_addr.encode('ascii') # Create the message ('plain' stands for Content-Type: text/plain) message = _MIMEText(body, content_type, body_encoding) message['From'] = _formataddr((sender_name, sender_addr)) message['To'] = _formataddr((recipient_name, recipient_addr)) message['Subject'] = _Header(subject, subject_encoding) if config.getboolean(section, 'use-8bit'): del message['Content-Transfer-Encoding'] charset = _Charset(body_encoding) charset.body_encoding = _email_encoders.encode_7or8bit message.set_payload(body, charset=charset) if extra_headers: for key,value in extra_headers.items(): encoding = guess_encoding(value, encodings) message[key] = _Header(value, encoding) return message
def get_message(sender, recipient, subject, body, content_type, extra_headers=None, config=None, section='DEFAULT'): """Generate a `Message` instance. All arguments should be Unicode strings (plain ASCII works as well). Only the real name part of sender and recipient addresses may contain non-ASCII characters. The email will be properly MIME encoded. The charset of the email will be the first one out of the list that can represent all the characters occurring in the email. >>> message = get_message( ... sender='John <*****@*****.**>', recipient='Ζεύς <*****@*****.**>', ... subject='Testing', ... body='Hello, world!\\n', ... content_type='plain', ... extra_headers={'Approved': '*****@*****.**'}) >>> print(message.as_string()) # doctest: +REPORT_UDIFF MIME-Version: 1.0 Content-Type: text/plain; charset="us-ascii" Content-Transfer-Encoding: 7bit From: John <*****@*****.**> To: =?utf-8?b?zpbOtc+Nz4I=?= <*****@*****.**> Subject: Testing Approved: [email protected] <BLANKLINE> Hello, world! <BLANKLINE> """ if config is None: config = _config.CONFIG if section not in config.sections(): section = 'DEFAULT' encodings = [ x.strip() for x in config.get(section, 'encodings').split(',') ] # Split real name (which is optional) and email address parts sender_name, sender_addr = _parseaddr(sender) recipient_list = [] for recipient_name, recipient_addr in _getaddresses([recipient]): recipient_encoding = guess_encoding(recipient_name, encodings) recipient_name = str( _Header(recipient_name, recipient_encoding).encode()) recipient_addr.encode('ascii') recipient_list.append(_formataddr((recipient_name, recipient_addr))) sender_encoding = guess_encoding(sender_name, encodings) recipient_encoding = guess_encoding(recipient_name, encodings) subject_encoding = guess_encoding(subject, encodings) body_encoding = guess_encoding(body, encodings) # We must always pass Unicode strings to Header, otherwise it will # use RFC 2047 encoding even on plain ASCII strings. sender_name = str(_Header(sender_name, sender_encoding).encode()) # Make sure email addresses do not contain non-ASCII characters sender_addr.encode('ascii') # Create the message ('plain' stands for Content-Type: text/plain) message = _MIMEText(body, content_type, body_encoding) message['From'] = _formataddr((sender_name, sender_addr)) message['To'] = ', '.join(recipient_list) message['Subject'] = _Header(subject, subject_encoding) if config.getboolean(section, 'use-8bit'): del message['Content-Transfer-Encoding'] charset = _Charset(body_encoding) charset.body_encoding = _email_encoders.encode_7or8bit message.set_payload(body, charset=charset) if extra_headers: for key, value in extra_headers.items(): encoding = guess_encoding(value, encodings) message[key] = _Header(value, encoding) return message
def embed_report(report, file_name='reporty', del_files='no', subject='', sender_name='', rec_name='', text=''): """ embeds report in custom email, and attaches html files and pngs Args: report (str): html code filename (str): name of html file (if you entered a custom file name in 'generate report', you must pass that filename through in this function) - default is 'reporty' del_files (str): 'yes' will delete files - default is 'no' (keep files) subject (str): subject of email - default is '' (no subject) sender_name (str): name of sender (will be email name no matter what on outlook) - default is '' (will result to email address on all platforms) rec_name (str): name of receiver (must be left blank for outlook users) - default is '' (will result in no send tag for gmail) text (str): any extra text you want to send will appear at start of email - default is '' (will result to no extra text) Returns: encoded multipart message """ # declaring message object message = _MIMEMultipart() # takes custom file name and adds html file extension file_name = file_name + ".html" # declaring empty file names list file_names = [] # takes filenames from if _os.path.exists("filenames.txt"): file = open("filenames.txt", "r") filenames = file.read() file.close() _os.remove("filenames.txt") file_names = filenames.strip('][').split(', ') else: pass # adds a sender_name, receiver name, and a subject if sender_name == '': pass else: message["From"] = str(sender_name) if rec_name == '': pass else: rec_name = (str(rec_name)).replace(" ", "_") message["To"] = rec_name if subject == '': pass else: message["Subject"] = str(subject) # attatches 'text' to message message.attach(_MIMEText(text, 'plain')) # attatches the html attachment to message attachment = _MIMEText(report, "html") message.attach(attachment) # adds a content id to all matplot pngs and attaches images if len(file_names) > 0: for i in range(len(file_names)): f_p = open(file_names[i], 'rb') image = _MIMEImage(f_p.read(), filename=file_names[i]) _encoders.encode_base64(image) f_p.close() image.add_header('Content-ID', '<' + file_names[i].replace('.png', '') + '>') image.add_header('Content-Disposition', 'inline', filename=file_names[i]) message.attach(image) else: pass # opens the html file and adds 'payload' attach_file = open(file_name, 'rb') payload = _MIMEBase('application', 'octate-stream') payload.set_payload(attach_file.read()) # encodes payload _encoders.encode_base64(payload) # add payload header with filename payload.add_header('Content-Disposition', 'attachment', filename=file_name) # attatches html file to the email message.attach(payload) attach_file.close() # creates final message (str) final_message = message.as_string() # deletes extra files if user specifies if del_files == 'yes': if _os.path.exists(file_name): _os.remove(file_name) else: pass for i in range(len(file_names)): if _os.path.exists(file_names[i]): _os.remove(file_names[i]) else: pass # returns the mime multipart message (str) return final_message
def send(self, receiver, cc=None, bcc=None, subject: str = None, message: str = None, image: str = None, audio: str = None, file: str = None): """ :param cc: Email Address as String or List. (Carbon Copy) :param bcc: Email Address as String or List. (Blind Carbon Copy) :param receiver: Email Address as String or List :param subject: Message Title :param message: Your Message :param image: Image File Name :param audio: Audio File Name :param file: File Name :return: Boolean """ msg = _MIMEMultipart() msg['Subject'] = subject msg['From'] = self.email try: if message is not None: text = _MIMEText(message) msg.attach(text) if image is not None: image_data = self._file_reader(image) image = _MIMEImage(_imagedata=image_data, name=image) msg.attach(image) if audio is not None: audio_data = self._file_reader(audio) audio = _MIMEAudio(_audiodata=audio_data, name=audio, _subtype='') msg.attach(audio) if file is not None: file_data = self._file_reader(file) file = _MIMEApp(_data=file_data, name=file) msg.attach(file) except Exception: print('Error: File Not Found!') self.status = False return False send_info = [] multi_info = {} if 'list' in str(type(receiver)): self.count_rec = len(receiver) receiver = ','.join(i for i in receiver) if 'list' in str(type(cc)): self.count_cc = len(cc) cc = ','.join(i for i in cc) if 'list' in str(type(bcc)): self.count_bcc = len(bcc) bcc = ','.join(i for i in bcc) if self.__login(): msg['To'] = receiver msg['CC'] = cc msg['BCC'] = bcc if self.multi: for _ in range(self.__repeat): try: self.__server.sendmail(from_addr=self.email, to_addrs=receiver, msg=msg.as_string()) except Exception: if self.__repeat == 1 & self.count_rec == 1: self.status = False else: send_info.append(False) else: if self.__repeat == 1 & self.count_rec == 1: self.status = True else: send_info.append(True) self.status = send_info finally: _sleep(self.__sleep) else: for rec in receiver.split(','): send_info = [] for _ in range(self.__repeat): try: self.__server.sendmail(from_addr=self.email, to_addrs=rec, msg=msg.as_string()) except Exception as e: if self.__repeat == 1 & self.count_rec == 1: self.status = False else: send_info.append(False) if 'OutboundSpamException' in str(e): print( 'Error: Please Login To Your Account And Verify it.' ) break else: if self.__repeat == 1 & self.count_rec == 1: self.status = True else: send_info.append(True) self.status = send_info multi_info[rec] = send_info finally: _sleep(self.__sleep) if self.count_rec != 1: self.status = multi_info self.__server.close()