def set_body(self, html=None, plain=None): cur_ctype = self.get_content_type() cur_maintype, cur_subtype = cur_ctype.split("/") flag = 0b00 if html is not None: htmlmsg = MIMEText(html, _subtype='html') flag |= 0b10 if plain is not None: plainmsg = MIMEText(plain, _subtype='plain') flag |= 0b01 if flag == 0b11: altmsg = MIMEMultipart('alternative') altmsg.attach(htmlmsg) altmsg.attach(plainmsg) if cur_ctype == "multipart/mixed": if flag == 0b01: # POTENTIAL BUG: does it matter if there is already a body payload? self.attach(plainmsg) elif flag == 0b10: # POTENTIAL BUG: ditto self.attach(htmlmsg) elif flag == 0b11: # POTENTIAL BUG: ditto self.attach(altmsg) else: raise Exception("YOU ARE NOT SUPPOSED TO BE HERE") elif cur_ctype == 'multipart/alternative': if flag == 0b01: self.set_payload(plainmsg.get_payload()) self['Content-Type'] = 'text/plain' elif flag == 0b10: self.set_payload(htmlmsg.get_payload()) self['Content-Type'] = 'text/html' elif flag == 0b11: self.set_payload(altmsg.get_payload()) else: raise Exception("YOU ARE NOT SUPPOSED TO BE HERE") elif cur_ctype.startswith('text'): if flag == 0b01: self.set_payload(plainmsg.get_payload()) if cur_ctype.endswith('html'): self['Content-Type'] = 'text/plain' elif flag == 0b10: self.set_payload(htmlmsg.get_payload()) if cur_ctype.endswith('plain'): self['Content-Type'] = 'text/html' elif flag == 0b11: self.make_alternative() #self['Content-Type'] = 'multipart/alternative' self.set_payload(altmsg.get_payload()) else: raise Exception("YOU ARE NOT SUPPOSED TO BE HERE")
def test_add_image_void_no_action(self): """ message payload must be void """ email_builder = EmailBuilder("localhost", 8000, "sender_email", "receiver_email") message = MIMEMultipart() email_builder._add_image(None, message) self.assertTrue(0 == len(message.get_payload())) email_builder._add_image([], message) self.assertTrue(0 == len(message.get_payload()))
def send_email(frm, to, subject, body, attachments=None): """ Send email, only possible to ASTRON addresses :param str frm: From address :param str/list to: To addresses, either single or list of addresses :param str subject: Subject of email :param dict body: Dict with e-mail content (str) and type (str) :param dict/list attachments: optional dict or list of dicts with attachment path (str), type (str), and name (str) """ # ensure "to" is a single string if isinstance(to, list): to_str = ', '.join(to) else: to_str = to # init email msg = MIMEMultipart('mixed') # set to, from, subject msg['To'] = to_str msg['From'] = frm msg['Subject'] = subject # add body msg.attach(MIMEText(body['content'], body['type'])) # add attachments if attachments is not None: # ensure it is a list if not isinstance(attachments, list): attachments = [attachments] for attachment in attachments: fname = attachment['path'] name = attachment['name'] typ = attachment['type'] # load the file with open(fname, 'rb') as f: part = MIMEApplication(f.read(), typ) # set filename part[ 'Content-Disposition'] = 'attachment; filename="{}"'.format( name) # attach to email msg.attach(part) # send the e-mail smtp = smtplib.SMTP() smtp.connect() try: smtp.sendmail(frm, to, msg.as_string()) except smtplib.SMTPSenderRefused: # assume failed because messages is too big # so send again without attachments # first element of payload is main text, rest are the attachments msg.set_payload(msg.get_payload()[0]) # send again smtp.sendmail(frm, to, msg.as_string()) smtp.close()
def test_add_image_file_not_empty(self): """ message payload must be not emppty """ email_builder = EmailBuilder("localhost", 8000, "sender_email", "receiver_email") message = MIMEMultipart() email_builder._add_image([b'01'], message) self.assertTrue(1 == len(message.get_payload()))
def sendConfirm_thread(email, token, name=None): email_server = validateAndGetField('EMAIL_SERVER') sender = validateAndGetField('EMAIL_FROM_ADDRESS') sender_name = validateAndGetField('EMAIL_SENDER_NAME', raise_error=False) domain = validateAndGetField('EMAIL_PAGE_DOMAIN') subject = validateAndGetField('EMAIL_MAIL_SUBJECT') address = validateAndGetField('EMAIL_ADDRESS') port = validateAndGetField('EMAIL_PORT', default_type=int) password = validateAndGetField('EMAIL_PASSWORD') mail_plain = validateAndGetField('EMAIL_MAIL_PLAIN', raise_error=False) mail_html = validateAndGetField('EMAIL_MAIL_HTML', raise_error=False) if not ( mail_plain or mail_html ): # Validation for mail_plain and mail_html as both of them have raise_error=False raise NotAllFieldCompiled( f"Both EMAIL_MAIL_PLAIN and EMAIL_MAIL_HTML missing from settings.py, at least one of them is required." ) domain += '/' if not domain.endswith('/') else '' msg = MIMEMultipart('alternative') msg['Subject'] = subject msg['From'] = formataddr( (sender_name.title(), sender)) if sender_name else sender msg['To'] = email from .views import verify http_protocol = "http://" if not domain.startswith("http") else '' link = f'{http_protocol}{domain}verify/{token}' for k, v in get_resolver(None).reverse_dict.items(): if k is verify and v[0][0][1][0]: addr = str(v[0][0][0]) link = domain + addr[0:addr.index('%')] + token email_data = {'link': link, 'name': name, 'domain': domain.strip('/')} if mail_plain: try: text = render_to_string(mail_plain, email_data) part1 = MIMEText(text, 'plain') msg.attach(part1) except AttributeError: pass if mail_html: try: html = render_to_string(mail_html, email_data) part2 = MIMEText(html, 'html') msg.attach(part2) except AttributeError: pass if not msg.get_payload(): raise EmailTemplateNotFound('No email template found') server = SMTP(email_server, port) server.starttls() server.login(address, password) server.sendmail(sender, email, msg.as_string()) server.quit()
def test_add_two_images_file_check_fields(self): """ message payload must have two images header """ email_builder = EmailBuilder("localhost", 8000, "sender_email", "receiver_email") message = MIMEMultipart() email_builder._add_image([b'0', b'0'], message) self.assertTrue(2 == len(message.get_payload())) for idx, base in enumerate(message.get_payload()): base_str = base.as_string() idx_str = str(idx) self.assertTrue('image/png' in base_str) self.assertTrue('filename="chart-image' + idx_str + '.png"' in base_str) self.assertTrue('X-Attachment-Id: ' + idx_str in base_str) self.assertTrue('Content-ID: <' + idx_str + '>' in base_str)
class Email(object): def __init__(self, ctx, repo, cache): self.recipients = ctx.getEmail(repo) self.mailfrom = ctx.getMailFrom() self.ignore = False if self.recipients is None or self.mailfrom is None: self.ignore = True return self.ctx = ctx self.cache = None if cache is not None: self.cache = weakref.ref(cache) self.repo = repo self.msg = MIMEMultipart() self.msg['Subject'] = '%s: bigitr error report' % repo self.msg['From'] = self.mailfrom self.msg['To'] = ', '.join(self.recipients) self.msg.preamble = 'Bigitr error report for repository %s' % repo @staticmethod def _filename(desc): desc = '_'.join(x for x in desc.split()) desc = ''.join(x for x in desc if x.isalnum() or x == '_') return desc + '.txt' @ifEmail def addAttachment(self, text, desc): msg = MIMEText(text) msg.add_header('Content-Disposition', 'attachment', filename=self._filename(desc)) self.msg.attach(msg) @ifEmail def addOutput(self, command, stdout, stderr): self.addAttachment(stderr, 'errors from ' + command) self.addAttachment(stdout, 'output from ' + command) @ifEmail def send(self, allout, allerr): # send email only if an error has been attached if self.msg.get_payload(): # First, attach the entire repository log; the individual # command messages will be embedded in it self.addAttachment(allerr, 'all errors') self.addAttachment(allout, 'all output') self._send() if self.cache and self.cache(): del self.cache()[self.repo] def _send(self): s = smtplib.SMTP(self.ctx.getSmartHost()) s.sendmail(self.ctx.getMailFrom(), self.recipients, self.msg.as_string()) s.quit()
def sendConfirm_thread(email, token): sender = validateAndGetField('EMAIL_SERVER') domain = validateAndGetField('EMAIL_PAGE_DOMAIN') subject = validateAndGetField('EMAIL_MAIL_SUBJECT') address = validateAndGetField('EMAIL_ADDRESS') port = validateAndGetField('EMAIL_PORT', default_type=int) password = validateAndGetField('EMAIL_PASSWORD') mail_plain = validateAndGetField('EMAIL_MAIL_PLAIN', raise_error=False) mail_html = validateAndGetField('EMAIL_MAIL_HTML', raise_error=False) if not (mail_plain or mail_html): raise NotAllFieldCompiled( f"Both EMAIL_MAIL_PLAIN and EMAIL_MAIL_HTML missing from settings.py, at least one of them is required." ) domain += '/' if not domain.endswith('/') else '' msg = MIMEMultipart('alternative') msg['Subject'] = subject msg['From'] = sender msg['To'] = email from .views import verify link = '' for k, v in get_resolver(None).reverse_dict.items(): if k is verify and v[0][0][1][0]: addr = str(v[0][0][0]) link = domain + addr[0:addr.index('%')] + token if mail_plain: try: text = render_to_string(mail_plain, {'link': link}) part1 = MIMEText(text, 'plain') msg.attach(part1) except AttributeError: pass if mail_html: try: html = render_to_string(mail_html, {'link': link}) part2 = MIMEText(html, 'html') msg.attach(part2) except AttributeError: pass if not msg.get_payload(): raise EmailTemplateNotFound('No email template found') server = SMTP(sender, port) server.starttls() server.login(address, password) server.sendmail(sender, email, msg.as_string()) server.quit()
def test_add_one_image_file_check_fields(self): """ message payload must have a image header """ email_builder = EmailBuilder("localhost", 8000, "sender_email", "receiver_email") message = MIMEMultipart() email_builder._add_image([b'01'], message) base = message.get_payload()[0] base_str = base.as_string() self.assertTrue('image/png' in base_str) self.assertTrue('filename="chart-image0.png"' in base_str) self.assertTrue('X-Attachment-Id: 0' in base_str) self.assertTrue('Content-ID: <0>' in base_str)
def parser_content(self, msg: MIMEMultipart) -> str: text_content = '' if self.len_string > 0: content = msg.get_payload() content_charset = content[0].get_content_charset() # 获得内容编码格式 text = content[0].as_string().split('base64')[-1] try: text_content = base64.b64decode(text).decode(content_charset) except Exception as err: logging.error(err) return text_content return text_content
class ShinyMail(object): """ShinyMail constructs and sends emails.""" def __init__(self, to, subject, message='', from_addr=None): """Initialize our mail object. to - a list of email addresses subject - a string containing the email subject message - a string containing the body of the email message (optional) from_addr - a string containing the from address (optional, will be replaced with EMAIL_HOST_USER from the shinymud config file if not given) """ self.email = MIMEMultipart() self.email['Subject'] = subject self.email['To'] = ', '.join(to) self.email['From'] = from_addr or EMAIL_HOST_USER self.message = message self.files = [] def attach_text_file(self, filename, content): """Attach a text file to this email. """ msg = MIMEText(content) msg.add_header('Content-Disposition', 'attachment', filename=filename) self.files.append(msg) def send(self): """Actually send an email. """ self._construct_email() con = smtplib.SMTP(EMAIL_HOST, EMAIL_PORT) con.set_debuglevel(1) if EMAIL_USE_TLS: con.starttls() if EMAIL_HOST_USER and EMAIL_HOST_PASSWORD: # Don't bother logging in if USER and PASS don't exist con.login(EMAIL_HOST_USER, EMAIL_HOST_PASSWORD) con.sendmail(self.email['From'], self.email['To'], self.email.as_string()) con.quit() def _construct_email(self): """Construct the email in a sensible order. Make sure the message text comes before any extra attachments. """ if self.message: self.email.attach(MIMEText(self.message)) for f in self.files: self.email.attach(f) if not self.email.get_payload(): # Don't let people send blank emails. That's mean. raise Exception("You can't send an email without any content!")
def test_add_attachement_no_ctype_no_encoding_compressed(self): config = EmailConfiguration() sender = MockEmailSender(config, mock_sender=MockSMTPServer("127.0.0.1", 80)) msg = MIMEMultipart() attachment = os.path.dirname(__file__) + os.sep + "something.zip" sender._add_attachement(msg, attachment, ctype=None, encoding=None) self.assertEquals([('Content-Type', 'multipart/mixed'), ('MIME-Version', '1.0')], msg.items()) self.assertEquals(1, len(msg.get_payload()))
def test_add_attachement_ctype_ecoding(self): config = EmailConfiguration() sender = MockEmailSender(config, mock_sender=MockSMTPServer("127.0.0.1", 80)) msg = MIMEMultipart() attachment = os.path.dirname(__file__) + os.sep + "test.txt" sender._add_attachement(msg, attachment, ctype='text/plain', encoding="utf-8") self.assertEquals([('Content-Type', 'multipart/mixed'), ('MIME-Version', '1.0')], msg.items()) self.assertEquals(1, len(msg.get_payload()))
def sendConfirm_thread(email, token): from .models import User try: sender = settings.EMAIL_SERVER domain = settings.EMAIL_PAGE_DOMAIN subject = settings.EMAIL_MAIL_SUBJECT address = settings.EMAIL_ADDRESS port = settings.EMAIL_PORT password = settings.EMAIL_PASSWORD except AttributeError: raise NotAllFieldCompiled('Compile all the fields in the settings') domain += '/' if not domain.endswith('/') else '' msg = MIMEMultipart('alternative') msg['Subject'] = subject msg['From'] = sender msg['To'] = email link = '' for k, v in get_resolver(None).reverse_dict.items(): if k is verify and v[0][0][1][0]: addr = str(v[0][0][0]) link = domain + addr[0: addr.index('%')] + token try: plain = settings.EMAIL_MAIL_PLAIN text = render_to_string(plain, {'link': link}) part1 = MIMEText(text, 'plain') msg.attach(part1) except AttributeError: pass try: html = settings.EMAIL_MAIL_HTML html = render_to_string(html, {'link': link}) part2 = MIMEText(html, 'html') msg.attach(part2) except AttributeError: pass if not msg.get_payload(): User.objects.get(email_token=token).delete() raise EmailTemplateNotFound('No email template found') server = SMTP(sender, port) server.starttls() server.login(address, password) server.sendmail(sender, email, msg.as_string()) server.quit()
def apply_mtom(headers, envelope, params, paramvals): ''' Apply MTOM to a SOAP envelope, separating attachments into a MIME multipart message. References: XOP http://www.w3.org/TR/xop10/ MTOM http://www.w3.org/TR/soap12-mtom/ http://www.w3.org/Submission/soap11mtom10/ @param headers Headers dictionary of the SOAP message that would originally be sent. @param envelope SOAP envelope string that would have originally been sent. @param params params attribute from the Message object used for the SOAP @param paramvals values of the params, passed to Message.to_xml @return tuple of length 2 with dictionary of headers and string of body that can be sent with HTTPConnection ''' # grab the XML element of the message in the SOAP body soapmsg = StringIO(envelope) soaptree = ElementTree.parse(soapmsg) soapns = soaptree.getroot().tag.split('}')[0].strip('{') soapbody = soaptree.getroot().find("{%s}Body" % soapns) message = None for child in list(soapbody): if child.tag != "%sFault" % (soapns, ): message = child break # Get additional parameters from original Content-Type ctarray = [] for n, v in headers.items(): if n.lower() == 'content-type': ctarray = v.split(';') break roottype = ctarray[0].strip() rootparams = {} for ctparam in ctarray[1:]: n, v = ctparam.strip().split('=') rootparams[n] = v.strip("\"'") # Set up initial MIME parts mtompkg = MIMEMultipart('related', boundary='?//<><>soaplib_MIME_boundary<>') rootpkg = None try: rootpkg = MIMEApplication(envelope, 'xop+xml', encode_7or8bit) except NameError: rootpkg = MIMENonMultipart("application", "xop+xml") rootpkg.set_payload(envelope) encode_7or8bit(rootpkg) # Set up multipart headers. del(mtompkg['mime-version']) mtompkg.set_param('start-info', roottype) mtompkg.set_param('start', '<soaplibEnvelope>') if 'SOAPAction' in headers: mtompkg.add_header('SOAPAction', headers.get('SOAPAction')) # Set up root SOAP part headers. del(rootpkg['mime-version']) rootpkg.add_header('Content-ID', '<soaplibEnvelope>') for n, v in rootparams.items(): rootpkg.set_param(n, v) rootpkg.set_param('type', roottype) mtompkg.attach(rootpkg) # Extract attachments from SOAP envelope. for i in range(len(params)): name, typ = params[i] if typ == Attachment: id = "soaplibAttachment_%s" % (len(mtompkg.get_payload()), ) param = message[i] param.text = "" incl = create_xml_subelement(param, "{http://www.w3.org/2004/08/xop/include}Include") incl.attrib["href"] = "cid:%s" % id if paramvals[i].fileName and not paramvals[i].data: paramvals[i].load_from_file() data = paramvals[i].data attachment = None try: attachment = MIMEApplication(data, _encoder=encode_7or8bit) except NameError: attachment = MIMENonMultipart("application", "octet-stream") attachment.set_payload(data) encode_7or8bit(attachment) del(attachment['mime-version']) attachment.add_header('Content-ID', '<%s>' % (id, )) mtompkg.attach(attachment) # Update SOAP envelope. soapmsg.close() soapmsg = StringIO() soaptree.write(soapmsg) rootpkg.set_payload(soapmsg.getvalue()) soapmsg.close() # extract body string from MIMEMultipart message bound = '--%s' % (mtompkg.get_boundary(), ) marray = mtompkg.as_string().split(bound) mtombody = bound mtombody += bound.join(marray[1:]) # set Content-Length mtompkg.add_header("Content-Length", str(len(mtombody))) # extract dictionary of headers from MIMEMultipart message mtomheaders = {} for name, value in mtompkg.items(): mtomheaders[name] = value if len(mtompkg.get_payload()) <= 1: return (headers, envelope) return (mtomheaders, mtombody)
def apply_mtom(headers, envelope, params, paramvals): """Apply MTOM to a SOAP envelope, separating attachments into a MIME multipart message. Returns a tuple of length 2 with dictionary of headers and string of body that can be sent with HTTPConnection References: XOP http://www.w3.org/TR/xop10/ MTOM http://www.w3.org/TR/soap12-mtom/ http://www.w3.org/Submission/soap11mtom10/ :param headers Headers dictionary of the SOAP message that would originally be sent. :param envelope Iterable containing SOAP envelope string that would have originally been sent. :param params params attribute from the Message object used for the SOAP :param paramvals values of the params, passed to Message.to_parent """ # grab the XML element of the message in the SOAP body envelope = ''.join(envelope) soaptree = etree.fromstring(envelope) soapbody = soaptree.find("{%s}Body" % _ns_soap_env) message = None for child in list(soapbody): if child.tag == ("{%s}Fault" % _ns_soap_env): return headers, envelope else: message = child break # Get additional parameters from original Content-Type ctarray = [] for n, v in headers.items(): if n.lower() == 'content-type': ctarray = v.split(';') break roottype = ctarray[0].strip() rootparams = {} for ctparam in ctarray[1:]: n, v = ctparam.strip().split('=') rootparams[n] = v.strip("\"'") # Set up initial MIME parts. mtompkg = MIMEMultipart('related', boundary='?//<><>spyne_MIME_boundary<>') rootpkg = MIMEApplication(envelope, 'xop+xml', encode_7or8bit) # Set up multipart headers. del mtompkg['mime-version'] mtompkg.set_param('start-info', roottype) mtompkg.set_param('start', '<spyneEnvelope>') if 'SOAPAction' in headers: mtompkg.add_header('SOAPAction', headers.get('SOAPAction')) # Set up root SOAP part headers. del rootpkg['mime-version'] rootpkg.add_header('Content-ID', '<spyneEnvelope>') for n, v in rootparams.items(): rootpkg.set_param(n, v) rootpkg.set_param('type', roottype) mtompkg.attach(rootpkg) # Extract attachments from SOAP envelope. for i in range(len(params)): name, typ = params[i] if issubclass(typ, (ByteArray, File)): id = "SpyneAttachment_%s" % (len(mtompkg.get_payload()), ) param = message[i] param.text = "" incl = etree.SubElement(param, "{%s}Include" % _ns_xop) incl.attrib["href"] = "cid:%s" % id if paramvals[i].fileName and not paramvals[i].data: paramvals[i].load_from_file() if issubclass(type, File): data = paramvals[i].data else: data = ''.join(paramvals[i]) attachment = MIMEApplication(data, _encoder=encode_7or8bit) del attachment['mime-version'] attachment.add_header('Content-ID', '<%s>' % (id, )) mtompkg.attach(attachment) # Update SOAP envelope. rootpkg.set_payload(etree.tostring(soaptree)) # extract body string from MIMEMultipart message bound = '--%s' % (mtompkg.get_boundary(), ) marray = mtompkg.as_string().split(bound) mtombody = bound mtombody += bound.join(marray[1:]) # set Content-Length mtompkg.add_header("Content-Length", str(len(mtombody))) # extract dictionary of headers from MIMEMultipart message mtomheaders = {} for name, value in mtompkg.items(): mtomheaders[name] = value if len(mtompkg.get_payload()) <= 1: return headers, envelope return mtomheaders, [mtombody]
def _prepare_message(self, addresses, subject, contents, attachments, headers): """ Prepare a MIME message """ if self.is_closed: raise YagConnectionClosed('Login required again') if isinstance(contents, text_type): contents = [contents] if isinstance(attachments, text_type): attachments = [attachments] # merge contents and attachments for now. if attachments is not None: for a in attachments: if not os.path.isfile(a): raise TypeError("'{0}' is not a valid filepath".format(a)) contents = attachments if contents is None else contents + attachments has_included_images, content_objects = self._prepare_contents(contents) msg = MIMEMultipart() if headers is not None: # Strangely, msg does not have an update method, so then manually. for k, v in headers.items(): msg[k] = v msg_alternative = MIMEMultipart('alternative') msg_related = MIMEMultipart('related') msg_related.attach("-- HTML goes here --") msg.attach(msg_alternative) self._add_subject(msg, subject) self._add_recipients_headers(msg, addresses) htmlstr = '' altstr = [] if has_included_images: msg.preamble = "This message is best displayed using a MIME capable email reader." if contents is not None: for content_object, content_string in zip(content_objects, contents): if content_object['main_type'] == 'image': # all image objects need base64 encoding, so do it now email.encoders.encode_base64(content_object['mime_object']) # aliased image {'path' : 'alias'} if isinstance(content_string, dict) and len(content_string) == 1: for key in content_string: hashed_ref = str(abs(hash(key))) alias = content_string[key] # pylint: disable=undefined-loop-variable content_string = key else: alias = os.path.basename(str(content_string)) hashed_ref = str(abs(hash(alias))) # TODO: I should probably remove inline now that there is "attachments" # if string is `inline`, inline, else, attach # pylint: disable=unidiomatic-typecheck if type(content_string) == inline: htmlstr += '<img src="cid:{0}" title="{1}"/>'.format(hashed_ref, alias) content_object['mime_object'].add_header( 'Content-ID', '<{0}>'.format(hashed_ref)) altstr.append('-- img {0} should be here -- '.format(alias)) # inline images should be in related MIME block msg_related.attach(content_object['mime_object']) else: # non-inline images get attached like any other attachment msg.attach(content_object['mime_object']) else: if content_object['encoding'] == 'base64': email.encoders.encode_base64(content_object['mime_object']) msg.attach(content_object['mime_object']) else: content_string = content_string.replace('\n', '<br>') try: htmlstr += '<div>{0}</div>'.format(content_string) except UnicodeEncodeError: htmlstr += u'<div>{0}</div>'.format(content_string) altstr.append(content_string) msg_related.get_payload()[0] = MIMEText(htmlstr, 'html', _charset=self.encoding) msg_alternative.attach(MIMEText('\n'.join(altstr), _charset=self.encoding)) msg_alternative.attach(msg_related) return msg
def prepare_message(user, useralias, addresses, subject, contents, attachments, headers, encoding, newline_to_break=True): # check if closed!!!!!! XXX """ Prepare a MIME message """ if isinstance(contents, text_type): contents = [contents] if isinstance(attachments, text_type): attachments = [attachments] # merge contents and attachments for now. if attachments is not None: for a in attachments: if not os.path.isfile(a): raise TypeError("'{0}' is not a valid filepath".format(a)) contents = attachments if contents is None else contents + attachments has_included_images, content_objects = prepare_contents(contents, encoding) msg = MIMEMultipart() if headers is not None: # Strangely, msg does not have an update method, so then manually. for k, v in headers.items(): msg[k] = v if headers is None or "Date" not in headers: msg["Date"] = formatdate() msg_alternative = MIMEMultipart("alternative") msg_related = MIMEMultipart("related") msg_related.attach("-- HTML goes here --") msg.attach(msg_alternative) add_subject(msg, subject) add_recipients_headers(user, useralias, msg, addresses) htmlstr = "" altstr = [] if has_included_images: msg.preamble = "This message is best displayed using a MIME capable email reader." if contents is not None: for content_object, content_string in zip(content_objects, contents): if content_object["main_type"] == "image": # all image objects need base64 encoding, so do it now email.encoders.encode_base64(content_object["mime_object"]) # aliased image {'path' : 'alias'} if isinstance(content_string, dict) and len(content_string) == 1: for key in content_string: hashed_ref = str(abs(hash(key))) alias = content_string[key] # pylint: disable=undefined-loop-variable content_string = key else: alias = os.path.basename(str(content_string)) hashed_ref = str(abs(hash(alias))) # TODO: I should probably remove inline now that there is "attachments" # if string is `inline`, inline, else, attach # pylint: disable=unidiomatic-typecheck if type(content_string) == inline: htmlstr += '<img src="cid:{0}" title="{1}"/>'.format( hashed_ref, alias) content_object["mime_object"].add_header( "Content-ID", "<{0}>".format(hashed_ref)) altstr.append( "-- img {0} should be here -- ".format(alias)) # inline images should be in related MIME block msg_related.attach(content_object["mime_object"]) else: # non-inline images get attached like any other attachment msg.attach(content_object["mime_object"]) else: if content_object["encoding"] == "base64": email.encoders.encode_base64(content_object["mime_object"]) msg.attach(content_object["mime_object"]) elif content_object["sub_type"] not in ["html", "plain"]: msg.attach(content_object["mime_object"]) else: if newline_to_break: content_string = content_string.replace("\n", "<br>") try: htmlstr += "<div>{0}</div>".format(content_string) except UnicodeEncodeError: htmlstr += u"<div>{0}</div>".format(content_string) altstr.append(content_string) msg_related.get_payload()[0] = MIMEText(htmlstr, "html", _charset=encoding) msg_alternative.attach(MIMEText("\n".join(altstr), _charset=encoding)) msg_alternative.attach(msg_related) return msg
def _decode_attachment(attachment_part: MIMEMultipart) -> bytes: return attachment_part.get_payload(decode=True)
def prepare_message(user, useralias, addresses, subject, contents, attachments, headers, encoding, newline_to_break=True): # check if closed!!!!!! XXX """ Prepare a MIME message """ if isinstance(contents, text_type): contents = [contents] if isinstance(attachments, text_type): attachments = [attachments] # merge contents and attachments for now. if attachments is not None: for a in attachments: if not os.path.isfile(a): raise TypeError("'{0}' is not a valid filepath".format(a)) contents = attachments if contents is None else contents + attachments has_included_images, content_objects = prepare_contents(contents, encoding) msg = MIMEMultipart() if headers is not None: # Strangely, msg does not have an update method, so then manually. for k, v in headers.items(): msg[k] = v if headers is None or "Date" not in headers: msg["Date"] = formatdate() msg_alternative = MIMEMultipart("alternative") msg_related = MIMEMultipart("related") msg_related.attach("-- HTML goes here --") msg.attach(msg_alternative) add_subject(msg, subject) add_recipients_headers(user, useralias, msg, addresses) htmlstr = "" altstr = [] if has_included_images: msg.preamble = "This message is best displayed using a MIME capable email reader." if contents is not None: for content_object, content_string in zip(content_objects, contents): if content_object["main_type"] == "image": # all image objects need base64 encoding, so do it now email.encoders.encode_base64(content_object["mime_object"]) # aliased image {'path' : 'alias'} if isinstance(content_string, dict) and len(content_string) == 1: for key in content_string: hashed_ref = str(abs(hash(key))) alias = content_string[key] # pylint: disable=undefined-loop-variable content_string = key else: alias = os.path.basename(str(content_string)) hashed_ref = str(abs(hash(alias))) # TODO: I should probably remove inline now that there is "attachments" # if string is `inline`, inline, else, attach # pylint: disable=unidiomatic-typecheck if type(content_string) == inline: htmlstr += '<img src="cid:{0}" title="{1}"/>'.format(hashed_ref, alias) content_object["mime_object"].add_header( "Content-ID", "<{0}>".format(hashed_ref) ) altstr.append("-- img {0} should be here -- ".format(alias)) # inline images should be in related MIME block msg_related.attach(content_object["mime_object"]) else: # non-inline images get attached like any other attachment msg.attach(content_object["mime_object"]) else: if content_object["encoding"] == "base64": email.encoders.encode_base64(content_object["mime_object"]) msg.attach(content_object["mime_object"]) elif content_object["sub_type"] not in ["html", "plain"]: msg.attach(content_object["mime_object"]) else: if newline_to_break: content_string = content_string.replace("\n", "<br>") try: htmlstr += "<div>{0}</div>".format(content_string) except UnicodeEncodeError: htmlstr += u"<div>{0}</div>".format(content_string) altstr.append(content_string) msg_related.get_payload()[0] = MIMEText(htmlstr, "html", _charset=encoding) msg_alternative.attach(MIMEText("\n".join(altstr), _charset=encoding)) msg_alternative.attach(msg_related) return msg
class HttpMessage(object): ''' generate and parse message in MIME multipart/related (RFC2387) structure. Its core variable is a MIMEMultipart Object ''' DEFAULT_MAIN_CONTENT_ID_HEADER_VALUE = 'Main' def __init__(self, multipart = None): ''' If parameter 'multipart' is None, then create an empty MIMEMultipart, whose body parts need to be added by invoking methods addMainpart() and add(). Otherwise reuse the exising multipart Object (this has been used by parseMIMEmessage() method.) ''' if multipart==None: self.multipart = MIMEMultipart('related') else: self.multipart = multipart def addMainpart(self, mainPartString, mainPartContentType='text/turtle'): self.multipart.set_param('type', mainPartContentType) self.multipart.set_param('start', self.DEFAULT_MAIN_CONTENT_ID_HEADER_VALUE) self.add(self.DEFAULT_MAIN_CONTENT_ID_HEADER_VALUE, mainPartString, mainPartContentType) def add(self, partId, partString, partContentType='text/turtle'): [mainType, subType]=partContentType.split('/') if mainType.lower()=='text': part = MIMEText(partString, subType) elif mainType.lower() == 'application': part = MIMEApplication(partString, subType, email.encoders.encode_7or8bit) if part is not None: part.add_header('Content-ID', partId) #mime package automatically add 'Content-Transfer-Encoding' header. We do not need it. #part.__delitem__('Content-Transfer-Encoding') self.multipart.attach(part) def getBody(self): ''' print out the whole multipart message as a String (including Content-Type header) @return string ''' return self.multipart.as_string() def getParts(self): ''' return the body parts as a list of MIME Object. Each body part includes body string and headers ''' payload = self.multipart.get_payload() return payload def getPart(self, partId): ''' return the body part whose Content-ID value is partId. Return only the body part string, no headers @return: string ''' payload = self.multipart.get_payload() for part in payload: if partId == part.get('Content-ID'): return part.get_payload() return None def getMainPart(self): ''' return the body part of "Main" part. No headers. ''' return self.getPart(self.DEFAULT_MAIN_CONTENT_ID_HEADER_VALUE) def getNonMainPartsAsDict(self): ''' return all those non "Main" parts as a dictionary (key is Content-ID, value is the body string). No headers ''' rt = {} payload = self.multipart.get_payload() for part in payload: if part.get('Content-ID')!= self.DEFAULT_MAIN_CONTENT_ID_HEADER_VALUE: rt[part.get('Content-ID')] = part.get_payload() return rt def getContentType(self): ''' return the Content-Type header value, including its parameters. ''' return self.multipart.get('Content-Type') def isMultipart(self): return self.multipart.is_multipart() def asString(self): return self.getBody()
def apply_mtom(headers, envelope, params, paramvals): """ Apply MTOM to a SOAP envelope, separating attachments into a MIME multipart message. References: XOP http://www.w3.org/TR/xop10/ MTOM http://www.w3.org/TR/soap12-mtom/ http://www.w3.org/Submission/soap11mtom10/ @param headers Headers dictionary of the SOAP message that would originally be sent. @param envelope SOAP envelope string that would have originally been sent. @param params params attribute from the Message object used for the SOAP @param paramvals values of the params, passed to Message.to_xml @return tuple of length 2 with dictionary of headers and string of body that can be sent with HTTPConnection """ # grab the XML element of the message in the SOAP body soaptree = etree.fromstring(envelope) soapbody = soaptree.find("{%s}Body" % soaplib.ns_soap_env) message = None for child in list(soapbody): if child.tag != "%sFault" % (soaplib.ns_soap_env,): message = child break # Get additional parameters from original Content-Type ctarray = [] for n, v in headers.items(): if n.lower() == "content-type": ctarray = v.split(";") break roottype = ctarray[0].strip() rootparams = {} for ctparam in ctarray[1:]: n, v = ctparam.strip().split("=") rootparams[n] = v.strip("\"'") # Set up initial MIME parts. mtompkg = MIMEMultipart("related", boundary="?//<><>soaplib_MIME_boundary<>") rootpkg = None try: rootpkg = MIMEApplication(envelope, "xop+xml", encode_7or8bit) except NameError: rootpkg = MIMENonMultipart("application", "xop+xml") rootpkg.set_payload(envelope) encode_7or8bit(rootpkg) # Set up multipart headers. del (mtompkg["mime-version"]) mtompkg.set_param("start-info", roottype) mtompkg.set_param("start", "<soaplibEnvelope>") if "SOAPAction" in headers: mtompkg.add_header("SOAPAction", headers.get("SOAPAction")) # Set up root SOAP part headers. del (rootpkg["mime-version"]) rootpkg.add_header("Content-ID", "<soaplibEnvelope>") for n, v in rootparams.items(): rootpkg.set_param(n, v) rootpkg.set_param("type", roottype) mtompkg.attach(rootpkg) # Extract attachments from SOAP envelope. for i in range(len(params)): name, typ = params[i] if typ == Attachment: id = "soaplibAttachment_%s" % (len(mtompkg.get_payload()),) param = message[i] param.text = "" incl = etree.SubElement(param, "{%s}Include" % soaplib.ns_xop) incl.attrib["href"] = "cid:%s" % id if paramvals[i].fileName and not paramvals[i].data: paramvals[i].load_from_file() data = paramvals[i].data attachment = None try: attachment = MIMEApplication(data, _encoder=encode_7or8bit) except NameError: attachment = MIMENonMultipart("application", "octet-stream") attachment.set_payload(data) encode_7or8bit(attachment) del (attachment["mime-version"]) attachment.add_header("Content-ID", "<%s>" % (id,)) mtompkg.attach(attachment) # Update SOAP envelope. rootpkg.set_payload(etree.tostring(soaptree)) # extract body string from MIMEMultipart message bound = "--%s" % (mtompkg.get_boundary(),) marray = mtompkg.as_string().split(bound) mtombody = bound mtombody += bound.join(marray[1:]) # set Content-Length mtompkg.add_header("Content-Length", str(len(mtombody))) # extract dictionary of headers from MIMEMultipart message mtomheaders = {} for name, value in mtompkg.items(): mtomheaders[name] = value if len(mtompkg.get_payload()) <= 1: return (headers, envelope) return (mtomheaders, mtombody)
import smtplib from email.mime.text import MIMEText from email.mime.multipart import MIMEMultipart msg = MIMEMultipart('alternative') me = '*****@*****.**' you = '*****@*****.**' msgbody = 'This is the body of the error system, and a test.' # me == the sender's email address # you == the recipient's email address msg['Subject'] = 'Error with your amazing software' msg['From'] = me msg['To'] = you mimebody = MIMEText(msgbody, 'plain') msg.attach(mimebody) composed = str(msg) msg.get_payload() s = smtplib.SMTP('smtp.gmail.com', 587) s.starttls() s.login('*****@*****.**', 'password') s.sendmail('*****@*****.**', '*****@*****.**', composed) s.quit()
def apply_mtom(headers, envelope, params, paramvals): '''Apply MTOM to a SOAP envelope, separating attachments into a MIME multipart message. Returns a tuple of length 2 with dictionary of headers and string of body that can be sent with HTTPConnection References: XOP http://www.w3.org/TR/xop10/ MTOM http://www.w3.org/TR/soap12-mtom/ http://www.w3.org/Submission/soap11mtom10/ :param headers Headers dictionary of the SOAP message that would originally be sent. :param envelope Iterable containing SOAP envelope string that would have originally been sent. :param params params attribute from the Message object used for the SOAP :param paramvals values of the params, passed to Message.to_parent_element ''' # grab the XML element of the message in the SOAP body envelope = ''.join(envelope) soaptree = etree.fromstring(envelope) soapbody = soaptree.find("{%s}Body" % _ns_soap_env) message = None for child in list(soapbody): if child.tag == ("{%s}Fault" % _ns_soap_env): return (headers, envelope) else: message = child break # Get additional parameters from original Content-Type ctarray = [] for n, v in headers.items(): if n.lower() == 'content-type': ctarray = v.split(';') break roottype = ctarray[0].strip() rootparams = {} for ctparam in ctarray[1:]: n, v = ctparam.strip().split('=') rootparams[n] = v.strip("\"'") # Set up initial MIME parts. mtompkg = MIMEMultipart('related', boundary='?//<><>spyne_MIME_boundary<>') rootpkg = MIMEApplication(envelope, 'xop+xml', encode_7or8bit) # Set up multipart headers. del(mtompkg['mime-version']) mtompkg.set_param('start-info', roottype) mtompkg.set_param('start', '<spyneEnvelope>') if 'SOAPAction' in headers: mtompkg.add_header('SOAPAction', headers.get('SOAPAction')) # Set up root SOAP part headers. del(rootpkg['mime-version']) rootpkg.add_header('Content-ID', '<spyneEnvelope>') for n, v in rootparams.items(): rootpkg.set_param(n, v) rootpkg.set_param('type', roottype) mtompkg.attach(rootpkg) # Extract attachments from SOAP envelope. for i in range(len(params)): name, typ = params[i] if typ in (ByteArray, Attachment): id = "spyneAttachment_%s" % (len(mtompkg.get_payload()), ) param = message[i] param.text = "" incl = etree.SubElement(param, "{%s}Include" % _ns_xop) incl.attrib["href"] = "cid:%s" % id if paramvals[i].fileName and not paramvals[i].data: paramvals[i].load_from_file() if type == Attachment: data = paramvals[i].data else: data = ''.join(paramvals[i]) attachment = None attachment = MIMEApplication(data, _encoder=encode_7or8bit) del(attachment['mime-version']) attachment.add_header('Content-ID', '<%s>' % (id, )) mtompkg.attach(attachment) # Update SOAP envelope. rootpkg.set_payload(etree.tostring(soaptree)) # extract body string from MIMEMultipart message bound = '--%s' % (mtompkg.get_boundary(), ) marray = mtompkg.as_string().split(bound) mtombody = bound mtombody += bound.join(marray[1:]) # set Content-Length mtompkg.add_header("Content-Length", str(len(mtombody))) # extract dictionary of headers from MIMEMultipart message mtomheaders = {} for name, value in mtompkg.items(): mtomheaders[name] = value if len(mtompkg.get_payload()) <= 1: return (headers, envelope) return (mtomheaders, [mtombody])
def apply_mtom(headers, envelope, params, paramvals): ''' Apply MTOM to a SOAP envelope, separating attachments into a MIME multipart message. References: XOP http://www.w3.org/TR/xop10/ MTOM http://www.w3.org/TR/soap12-mtom/ http://www.w3.org/Submission/soap11mtom10/ @param headers Headers dictionary of the SOAP message that would originally be sent. @param envelope SOAP envelope string that would have originally been sent. @param params params attribute from the Message object used for the SOAP @param paramvals values of the params, passed to Message.to_xml @return tuple of length 2 with dictionary of headers and string of body that can be sent with HTTPConnection ''' # grab the XML element of the message in the SOAP body soapmsg = StringIO(envelope) soaptree = ElementTree.parse(soapmsg) soapns = soaptree.getroot().tag.split('}')[0].strip('{') soapbody = soaptree.getroot().find("{%s}Body" % soapns) message = None for child in list(soapbody): if child.tag != "%sFault" % (soapns, ): message = child break # Get additional parameters from original Content-Type ctarray = [] for n, v in headers.items(): if n.lower() == 'content-type': ctarray = v.split(';') break roottype = ctarray[0].strip() rootparams = {} for ctparam in ctarray[1:]: n, v = ctparam.strip().split('=') rootparams[n] = v.strip("\"'") # Set up initial MIME parts mtompkg = MIMEMultipart('related', boundary='?//<><>soaplib_MIME_boundary<>') rootpkg = None try: rootpkg = MIMEApplication(envelope, 'xop+xml', encode_7or8bit) except NameError: rootpkg = MIMENonMultipart("application", "xop+xml") rootpkg.set_payload(envelope) encode_7or8bit(rootpkg) # Set up multipart headers. del (mtompkg['mime-version']) mtompkg.set_param('start-info', roottype) mtompkg.set_param('start', '<soaplibEnvelope>') if 'SOAPAction' in headers: mtompkg.add_header('SOAPAction', headers.get('SOAPAction')) # Set up root SOAP part headers. del (rootpkg['mime-version']) rootpkg.add_header('Content-ID', '<soaplibEnvelope>') for n, v in rootparams.items(): rootpkg.set_param(n, v) rootpkg.set_param('type', roottype) mtompkg.attach(rootpkg) # Extract attachments from SOAP envelope. for i in range(len(params)): name, typ = params[i] if typ == Attachment: id = "soaplibAttachment_%s" % (len(mtompkg.get_payload()), ) param = message[i] param.text = "" incl = create_xml_subelement( param, "{http://www.w3.org/2004/08/xop/include}Include") incl.attrib["href"] = "cid:%s" % id if paramvals[i].fileName and not paramvals[i].data: paramvals[i].load_from_file() data = paramvals[i].data attachment = None try: attachment = MIMEApplication(data, _encoder=encode_7or8bit) except NameError: attachment = MIMENonMultipart("application", "octet-stream") attachment.set_payload(data) encode_7or8bit(attachment) del (attachment['mime-version']) attachment.add_header('Content-ID', '<%s>' % (id, )) mtompkg.attach(attachment) # Update SOAP envelope. soapmsg.close() soapmsg = StringIO() soaptree.write(soapmsg) rootpkg.set_payload(soapmsg.getvalue()) soapmsg.close() # extract body string from MIMEMultipart message bound = '--%s' % (mtompkg.get_boundary(), ) marray = mtompkg.as_string().split(bound) mtombody = bound mtombody += bound.join(marray[1:]) # set Content-Length mtompkg.add_header("Content-Length", str(len(mtombody))) # extract dictionary of headers from MIMEMultipart message mtomheaders = {} for name, value in mtompkg.items(): mtomheaders[name] = value if len(mtompkg.get_payload()) <= 1: return (headers, envelope) return (mtomheaders, mtombody)
def prepare_message(user, useralias, addresses, subject, contents, attachments, encoding): """ Prepare a MIME message """ if isinstance(contents, text_type): contents = [contents] if isinstance(attachments, text_type): attachments = [attachments] if attachments is not None: contents = attachments if contents is None else contents + attachments print('contents: {0}'.format(contents)) has_included_images, content_objects = prepare_contents(contents, encoding) print('has_included_images={0}\ncontent_objects={1}'.format( has_included_images, content_objects)) # mixed msg = MIMEMultipart() add_date(msg) add_subject(msg, subject) # 纯文本与超文本共存 msg_alternative = MIMEMultipart("alternative") # 可以包含内嵌资源。 msg_related = MIMEMultipart("related") msg_related.attach("-- HTML goes here --") msg.attach(msg_alternative) add_recipients_headers(user, useralias, msg, addresses) htmlstr = "" altstr = [] if contents is not None: for content_object, content_string in zip(content_objects, contents): print('*****************t200:', content_object) if content_object["main_type"] == "image": pass else: if content_object["encoding"] == "base64": email.encoders.encode_base64(content_object["mime_object"]) msg.attach(content_object["mime_object"]) else: content_string = content_string.replace("\n", "<br>") try: htmlstr += "<div>{0}</div>".format(content_string) except UnicodeEncodeError: htmlstr += u"<div>{0}</div>".format(content_string) altstr.append(content_string) msg_related.get_payload()[0] = MIMEText(htmlstr, "html", _charset=encoding) msg_alternative.attach(MIMEText("\n".join(altstr), _charset=encoding)) msg_alternative.attach(msg_related) return msg
class ComposerPanel(wx.Panel): #TODO user RFC email header, add subject, multiprocess attachment """Panel for mail composer""" def __init__(self, parent): wx.Panel.__init__(self, parent) #Message object self.msg = MIMEMultipart() self.payloadLs = self.msg.get_payload() self.bodyid = len(self.payloadLs) - 1 #Create some sizer mainVSizer = wx.BoxSizer(wx.VERTICAL) buttonHSizer = wx.BoxSizer(wx.HORIZONTAL) recvHSizer = wx.BoxSizer(wx.HORIZONTAL) fromHSizer = wx.BoxSizer(wx.HORIZONTAL) subjectHSizer = wx.BoxSizer(wx.HORIZONTAL) attachHSizer = wx.BoxSizer(wx.HORIZONTAL) self.fromLbl = wx.StaticText(self, label="From:") fromHSizer.Add(self.fromLbl, 0, wx.EXPAND) ##From text control self.fromTc = wx.TextCtrl(self, size=(-1,-1)) fromHSizer.Add(self.fromTc, 1, wx.EXPAND) self.recvLbl = wx.StaticText(self, label="Recipients:") recvHSizer.Add(self.recvLbl, 0, wx.EXPAND) #Receivers text control self.recvTc = wx.TextCtrl(self, size=(-1, -1)) recvHSizer.Add(self.recvTc, 1, wx.EXPAND) self.subjectLbl = wx.StaticText(self, label="Subject:") subjectHSizer.Add(self.subjectLbl, 0, wx.EXPAND) #Subject tc self.subjectTc = wx.TextCtrl(self, size=(-1, -1)) subjectHSizer.Add(self.subjectTc, 1, wx.EXPAND) #Attach self.attachLbl = wx.StaticText(self, label='Attachment:') self.attachTc = wx.TextCtrl(self) self.attachBtn = wx.Button(self, label='Add') self.Bind(wx.EVT_BUTTON, self.AddClick, self.attachBtn) attachHSizer.Add(self.attachLbl, 0) attachHSizer.Add(self.attachTc, 1, wx.EXPAND) attachHSizer.Add(self.attachBtn, 0) #Content tc - multiline self.contentTc = wx.TextCtrl(self, style=wx.TE_MULTILINE) #buttons Clear - Send self.clearBtn = wx.Button(self, label="Clear") self.Bind(wx.EVT_BUTTON, self.ClearClick, self.clearBtn) buttonHSizer.Add(self.clearBtn, 0) self.sendBtn = wx.Button(self, label="Send") self.Bind(wx.EVT_BUTTON, self.SendClick, self.sendBtn) buttonHSizer.Add(self.sendBtn, 0) mainVSizer.Add(fromHSizer, 0, wx.EXPAND) mainVSizer.Add(recvHSizer, 0, wx.EXPAND) mainVSizer.Add(subjectHSizer, 0, wx.EXPAND) mainVSizer.Add(attachHSizer, 0, wx.EXPAND) mainVSizer.Add(self.contentTc, 1, wx.EXPAND) mainVSizer.Add(buttonHSizer, 0, wx.ALL, 5) self.SetSizerAndFit(mainVSizer) def AddClick(self, event): """Attach a file to email""" body = MIMEText(self.contentTc.GetValue()) self.msg.attach(body) self.payloadLs = self.msg.get_payload() self.bodyid = len(self.payloadLs) - 1 #Choose file self.dirname = '' dlg = wx.FileDialog(self, "Choose a file", self.dirname, "", "*.*", wx.OPEN) if dlg.ShowModal() == wx.ID_OK: #user cannot do anything on app util click ok or cancel #dlg.ShowModal() return ID of button pressed self.filename = dlg.GetFilename() self.dirname = dlg.GetDirectory() #f = open(os.path.join(self.dirname, self.filename), 'r') #TODO attach here att = attach.attachfile(os.path.join(self.dirname, self.filename), self.filename) self.msg.attach(att) dlg.Destroy() self.attachTc.AppendText(self.filename + ' ') def SendClick(self, event): """Send mail """ sender = self.fromTc.GetValue() recp = self.recvTc.GetValue() subj = self.subjectTc.GetValue() body = MIMEText(self.contentTc.GetValue()) self.msg['Subject'] = subj self.msg['To'] = recp self.msg['From'] = sender self.msg.attach(body) if self.payloadLs: last = len(self.payloadLs) - 1 self.payloadLs[self.bodyid] = self.payloadLs[-1] self.payloadLs.__delitem__(last) self.msg.set_payload(self.payloadLs) composed = self.msg.as_string() #TODO need a parser to parse email address to host address s = smtplib.SMTP('localhost') #TODO fix no rset bug s.sendmail(sender, recp, composed) #TODO change status bar if mail sented def ClearClick(self, event): """Clear content control""" self.contentTc.Clear()
<th>Gb</th> </tr> {coordinfo} </table> </p> </body> </html>""".format(**kwargs) msg.attach(MIMEText(txt, 'html')) for fname in attachments or (): with open(fname, 'rb') as f: part = MIMEApplication(f.read(), 'pdf', Name=os.path.basename(fname)) part['Content-Disposition'] = 'attachment; filename="{}"'.format(os.path.basename(fname).replace('_candidates_summary', '')) msg.attach(part) log("Sending email to: {}".format(to)) smtp = smtplib.SMTP() smtp.connect() try: smtp.sendmail(frm, to, msg.as_string()) except smtplib.SMTPSenderRefused: # assume attachments are too large # resend without attachments # first element of payload is main text, rest are attachments msg.set_payload(msg.get_payload()[0]) smtp.sendmail(frm, to, msg.as_string()) smtp.close()