def render(self, plain_body: str, plain_signature: str, subject: str, order: Order, position: OrderPosition) -> str: body_md = markdown_compile_email(plain_body) htmlctx = { 'site': settings.PRETIX_INSTANCE_NAME, 'site_url': settings.SITE_URL, 'body': body_md, 'subject': str(subject), 'color': '#8E44B3' } if self.event: htmlctx['event'] = self.event htmlctx['color'] = self.event.settings.primary_color if plain_signature: signature_md = plain_signature.replace('\n', '<br>\n') signature_md = markdown_compile_email(signature_md) htmlctx['signature'] = signature_md if order: htmlctx['order'] = order if position: htmlctx['position'] = position tpl = get_template(self.template_name) body_html = inline_css(tpl.render(htmlctx)) return body_html
def confirmed_payments_email(acct): subject = "New customer payment information received" title = "New customer payment information received" body = "Email: %s\n\n" % (acct.user.email) try: body += "Name: %s\n\n" % (acct.user.full_name) except: pass body += "Company: %s\n\n" % (acct.company_profile.company) plaintext = get_template('email_template/admin_com.txt') htmly = get_template('email_template/admin_com.html') d = Context({'title': title, 'body': body,}) text_content = plaintext.render(d) html_content = htmly.render(d) html_content = inline_css(html_content) connection = get_connection(username=DEFAULT_FROM_EMAIL, password=EMAIL_HOST_PASSWORD, fail_silently=False) if LIVE: msg = EmailMultiAlternatives(subject, text_content, DEFAULT_FROM_EMAIL, [DEFAULT_FROM_EMAIL, '*****@*****.**','*****@*****.**'], [HIGHRISE_CONFIG['email']], connection=connection) else: msg = EmailMultiAlternatives(subject, text_content, DEFAULT_FROM_EMAIL, [DEFAULT_FROM_EMAIL,], connection=connection) msg.attach_alternative(html_content, "text/html") msg.send()
def test_inline_css_in_head(): document = """ <html> <head> <style> .emphasis { font-weight: bold; } </style> </head> <body> Hello <span class="emphasis">World</span>! </body> </html> """ expected = """<html> <head/> <body> Hello <span class="emphasis" style="font-weight: bold">World</span>! </body> </html> """ assert expected == inline_css(document)
def send(self, to_addresses, context={}, attachments=None, headers=None, **kwargs): html_body = self.render(context) text_body = self.render_txt(context) or striptags(html_body) try: from inlinestyler.utils import inline_css html_body = inline_css(html_body) except ImportError: logger.info('pip install instyler to render CSS inline in emails') subject = self._render_from_string(self.subject, context) if isinstance(to_addresses, (str,unicode)): to_addresses = (to_addresses,) whitelisted_email_addresses = getattr(settings, 'EMAILTEMPLATES_DEBUG_WHITELIST', []) if getattr(settings, 'EMAILTEMPLATES_DEBUG', False): # clean non-whitelisted emails from the to_address cleaned_to_addresses = [] for address in to_addresses: try: email_domain = address.split('@')[1] except IndexError: email_domain = None if email_domain in whitelisted_email_addresses or address in whitelisted_email_addresses: cleaned_to_addresses.append(address) to_addresses = cleaned_to_addresses bcc = [self.bcc, ] msg = EmailMultiAlternatives(subject, text_body, self.visible_from_address(), to_addresses, bcc=bcc, headers=headers, **kwargs) msg.attach_alternative(html_body, "text/html") if attachments is not None: for attach in attachments: msg.attach(*attach) return msg.send()
def alert_admin_new_signup(inps): subject = "New User signup" title = "%s has signed up" % (inps['email']) body = "" for k in inps.iterkeys(): body += "%s: %s\n\n" % (k, inps[k]) plaintext = get_template('email_template/admin_com.txt') htmly = get_template('email_template/admin_com.html') d = Context({'title': title, 'body': body,}) text_content = plaintext.render(d) html_content = htmly.render(d) html_content = inline_css(html_content) connection = get_connection(username=DEFAULT_FROM_EMAIL, password=EMAIL_HOST_PASSWORD, fail_silently=False) if LIVE: msg = EmailMultiAlternatives(subject, text_content, DEFAULT_FROM_EMAIL, [DEFAULT_FROM_EMAIL, '*****@*****.**','*****@*****.**'], [HIGHRISE_CONFIG['email']], connection=connection) else: msg = EmailMultiAlternatives(subject, text_content, DEFAULT_FROM_EMAIL, [DEFAULT_FROM_EMAIL, '*****@*****.**'], connection=connection) msg.attach_alternative(html_content, "text/html") msg.send()
def get_formatted_html(subject, message, footer=None): message = scrub_urls(message) return inline_css(webnotes.get_template("templates/emails/standard.html").render({ "content": message, "footer": get_footer(footer), "title": subject }))
def format_html_email(markdown_text, subject): extensions = ["markdown.extensions.nl2br", "markdown.extensions.smarty"] markdown_html = Markup(markdown.markdown(markdown_text, extensions=extensions)) return inline_css( render_template( "admin/email/email_template.html", subject=subject, content=markdown_html ) )
def profile_builder_alert_email(): now = current_time_aware() yesterday = now - datetime.timedelta(days=1) builder = ProfileBuilder.Query.filter(createdAt__gte=yesterday) if LIVE: builder = [b for b in builder if b.user['type'] == 'live'] else: builder = [b for b in builder] if builder: subject = "New profile builder blocks ordered" title = "New profile builder blocks ordered" body = "" for b in builder: body += "Email: %s\n" % (b.user['email']) try: body += "Name: %s\n" % (b.user['full_name']) except: pass try: company = CompanyProfiles.Query.get(user_id=str(b.user_id)) body += "Company: %s\n" % (company.company) except: pass for i in ('facebook_profile', 'twitter_profile', 'instagram_profile', 'marketing_strategy', 'linkedin_profile'): if getattr(b, i): split = i.split('_') name = "" for s in split: name += "%s " % (s.title()) body += "%s\n" % (name) body += "\n\n\n" plaintext = get_template('email_template/admin_com.txt') htmly = get_template('email_template/admin_com.html') d = Context({'title': title, 'body': body,}) text_content = plaintext.render(d) html_content = htmly.render(d) html_content = inline_css(html_content) connection = get_connection(username=DEFAULT_FROM_EMAIL, password=EMAIL_HOST_PASSWORD, fail_silently=False) if LIVE: msg = EmailMultiAlternatives(subject, text_content, DEFAULT_FROM_EMAIL, [DEFAULT_FROM_EMAIL, '*****@*****.**','*****@*****.**'], [HIGHRISE_CONFIG['email']], connection=connection) else: msg = EmailMultiAlternatives(subject, text_content, DEFAULT_FROM_EMAIL, [DEFAULT_FROM_EMAIL,], connection=connection) msg.attach_alternative(html_content, "text/html") msg.send()
def send_template_email(to_email, subject, title, body): plaintext = get_template('email_template/plain_text.txt') htmly = get_template('email_template/index.html') d = Context({'title': title, 'body': body}) text_content = plaintext.render(d) html_content = htmly.render(d) html_content = inline_css(html_content) connection = get_connection(username=DEFAULT_FROM_EMAIL, password=EMAIL_HOST_PASSWORD, fail_silently=False) msg = EmailMultiAlternatives(subject, text_content, DEFAULT_FROM_EMAIL, [to_email], [HIGHRISE_CONFIG['email']], connection=connection) msg.attach_alternative(html_content, "text/html") msg.send()
def get_formatted_html(subject, message, footer=None, print_html=None): message = scrub_urls(message) rendered_email = frappe.get_template("templates/emails/standard.html").render({ "content": message, "footer": get_footer(footer), "title": subject, "print_html": print_html }) # if in a test case, do not inline css if frappe.local.flags.in_test: return rendered_email return inline_css(rendered_email)
def _inline_css(self, html, css): if not self.template.styles: return html # an empty style will cause an error in inline_styler so we use a space instead html_with_css = inline_styler.inline_css(css + html) # inline_styler will return a complete html filling missing html and body tags which we don't want if html.startswith('<'): body = ET.fromstring(html_with_css).find('.//body') body = ''.join(ET.tostring(e, encoding='unicode') for e in body) else: body = ET.fromstring(html_with_css).find('.//body/p') body = body.text return body.strip()
def send_welcome_email(to_email, count, ref): plaintext = get_template('email_template/plain_text.txt') htmly = get_template('email_template/index.html') d = Context({'count': count, 'ref': ref}) subject = "Great move | Surprisr" text_content = plaintext.render(d) html_content = htmly.render(d) html_content = inline_css(html_content) connection = get_connection(username=DEFAULT_FROM_EMAIL, password=EMAIL_HOST_PASSWORD, fail_silently=False) if LIVE: msg = EmailMultiAlternatives(subject, text_content, DEFAULT_FROM_EMAIL, [to_email], [HIGHRISE_CONFIG['email']], connection=connection) else: msg = EmailMultiAlternatives(subject, text_content, DEFAULT_FROM_EMAIL, [to_email], connection=connection) msg.attach_alternative(html_content, "text/html") msg.send()
def confirm_referral(ref): referrer = ParseUser.Query.all().filter(ref=ref) referrer = [r for r in referrer] if len(referrer) > 0: referrer = referrer[0] to_email = referrer.email # send email to referrer refs = UserReferrals.Query.all().filter(code=ref) count = int(len([r for r in refs])) if count < 5: subject = "Almost There | Exclusive discounts and priority access at Surprisr" title = "%s/5 sign-ups" % (str(int(count))) body = "Get 5 of your friends to sign up to cut the line and get exclusive discounts on your first gifts. Keep sharing the link below!" if count == 5: subject = "You've earned priority access to Surprisr!" title = "You got 5 sign-ups!" body = "You get to cut the line and will be offered exclusive discounts on your first gifts at Surprisr. Keep sharing - more rewards coming soon :)" if count > 5: subject = "You are incredible" title = "You got %s sign-ups!" % (str(int(count))) body = "Wow! Those that get more sign-ups will get rewarded. You have our word." if count > 0: plaintext = get_template('email_template/counter.txt') htmly = get_template('email_template/counter.html') d = Context({'title': title, 'body': body, 'ref': ref}) text_content = plaintext.render(d) html_content = htmly.render(d) html_content = inline_css(html_content) connection = get_connection(username=DEFAULT_FROM_EMAIL, password=EMAIL_HOST_PASSWORD, fail_silently=False) if LIVE: msg = EmailMultiAlternatives(subject, text_content, DEFAULT_FROM_EMAIL, [to_email], [HIGHRISE_CONFIG['email']], connection=connection) else: msg = EmailMultiAlternatives(subject, text_content, DEFAULT_FROM_EMAIL, [to_email], connection=connection) msg.attach_alternative(html_content, "text/html") msg.send()
def check_first_blocks(user, form): # send email to boost blocks team if this is first time user has selected blocks subject = "First time Boost Blocks ordered" title = "First time Boost Blocks ordered" body = "Email: %s\n" % (user.email) try: body += "Name: %s\n" % (user.full_name) except: pass try: company = CompanyProfiles.Query.get(user_id=str(user.objectId)) body += "Company: %s\n" % (company.company) except: pass for i in ('facebook_scale', 'twitter_scale', 'instagram_scale'): body += "%s - set to: %s\n" % (i, form[i]) body += "\n\n" plaintext = get_template('email_template/admin_com.txt') htmly = get_template('email_template/admin_com.html') d = Context({'title': title, 'body': body,}) text_content = plaintext.render(d) html_content = htmly.render(d) html_content = inline_css(html_content) connection = get_connection(username=DEFAULT_FROM_EMAIL, password=EMAIL_HOST_PASSWORD, fail_silently=False) if LIVE: msg = EmailMultiAlternatives(subject, text_content, DEFAULT_FROM_EMAIL, [DEFAULT_FROM_EMAIL, '*****@*****.**','*****@*****.**'], [HIGHRISE_CONFIG['email']], connection=connection) else: msg = EmailMultiAlternatives(subject, text_content, DEFAULT_FROM_EMAIL, [DEFAULT_FROM_EMAIL,], connection=connection) msg.attach_alternative(html_content, "text/html") msg.send()
def render(self, plain_body: str, plain_signature: str, subject: str, order: Order) -> str: body_md = bleach.linkify(markdown_compile(plain_body)) htmlctx = { 'site': settings.PRETIX_INSTANCE_NAME, 'site_url': settings.SITE_URL, 'body': body_md, 'subject': str(subject), 'color': '#8E44B3' } if self.event: htmlctx['event'] = self.event htmlctx['color'] = self.event.settings.primary_color if plain_signature: signature_md = plain_signature.replace('\n', '<br>\n') signature_md = bleach.linkify(bleach.clean(markdown.markdown(signature_md), tags=bleach.ALLOWED_TAGS + ['p', 'br'])) htmlctx['signature'] = signature_md if order: htmlctx['order'] = order tpl = get_template(self.template_name) body_html = inline_css(tpl.render(htmlctx)) return body_html
def save(self, *args, **kwargs): if self.content.startswith('http://'): url = self.content.strip() html_page = urlopen(url).read() self.content = inline_css(html_page, url) super(Newsletter, self).save(*args, **kwargs)
def check_block_updates(): now = current_time_aware() subject = title = "Updates to customer blocks" body = "" def build_email_body_by_date(accts, update_per_end=False): body = "" for a in accts: user = get_parse_user_by_email(a.user['email']) blocks = get_current_blocks(user) if blocks['latest']: body += "Email: %s\n" % (user.email) try: body += "Name: %s\n" % (user['full_name']) except: pass try: company = CompanyProfiles.Query.get(user_id=str(a.user_id)) body += "Company: %s\n" % (company.company) except: pass for i in ('facebook_scale', 'twitter_scale', 'instagram_scale'): body += "%s - set to: %s" % (i, getattr(blocks['latest'],i)) try: body += " (change from last period: %s)" % (blocks['change'][i]) except: pass body += "\n" body += "\n\n" if update_per_end: # update billing period end a.chargify_per_end += datetime.timedelta(days=7) a.save() return body def filter_accts(LIVE, accts): if LIVE: accts = [a for a in accts if a.user['type'] == 'live'] else: accts = [a for a in accts] return accts # update billing period and show updates to blocks accts = AccountDetails.Query.filter(chargify_active=True, chargify_per_end__lte=now) accts = filter_accts(LIVE, accts) if accts: body += "Today's block updates:\n\n" body += build_email_body_by_date(accts, update_per_end=True) body += "\n\n\n" # show expected updates to blocks accts = AccountDetails.Query.filter(chargify_active=True, chargify_per_end__lte=(now+datetime.timedelta(days=1)), chargify_per_end__gte=now) accts = filter_accts(LIVE, accts) if accts: body += "Tomorrow's expected block updates:\n\n" body += build_email_body_by_date(accts) body += "\n\n\n" accts = AccountDetails.Query.filter(chargify_active=True, chargify_per_end__lte=(now+datetime.timedelta(days=2)), chargify_per_end__gte=(now+datetime.timedelta(days=1))) accts = filter_accts(LIVE, accts) if accts: body += "Day after tomorrow's expected block updates:\n\n" body += build_email_body_by_date(accts) body += "\n\n\n" if body: plaintext = get_template('email_template/admin_com.txt') htmly = get_template('email_template/admin_com.html') d = Context({'title': title, 'body': body,}) text_content = plaintext.render(d) html_content = htmly.render(d) html_content = inline_css(html_content) connection = get_connection(username=DEFAULT_FROM_EMAIL, password=EMAIL_HOST_PASSWORD, fail_silently=False) if LIVE: msg = EmailMultiAlternatives(subject, text_content, DEFAULT_FROM_EMAIL, [DEFAULT_FROM_EMAIL, '*****@*****.**','*****@*****.**'], [HIGHRISE_CONFIG['email']], connection=connection) else: msg = EmailMultiAlternatives(subject, text_content, DEFAULT_FROM_EMAIL, [DEFAULT_FROM_EMAIL,], connection=connection) msg.attach_alternative(html_content, "text/html") msg.send()
#!/usr/bin/env python # -*- coding: utf-8 -*- import sys try: from inlinestyler.utils import inline_css except ImportError: sys.stderr.write("inlinestyler is missing. `pip install inlinestyler == 0.2.0`") if __name__ == "__main__": if len(sys.argv) != 3: sys.stderr.write("python inlinestyler_cli.py input_file_fullpath.html output_file_fullpath.html") else: with open(sys.argv[1]) as input_file: content = input_file.read() output = inline_css(content) with open(sys.argv[2], 'w') as output_file: output_file.write(output.encode('utf-8')) print("completed") exit(0)
def get_message(msg_id): credentials = client.OAuth2Credentials.from_json(session['credentials']) http = credentials.authorize(httplib2.Http(cache='.cache')) gmail_service = discovery.build('gmail', 'v1', http=http) try: message = gmail_service.users().messages().get(userId='me', id=msg_id, format='full').execute() message_payload = message['payload'] if 'parts' in message_payload: for part in message_payload['parts']: if (part['mimeType'] == 'text/html') or (part['mimeType'] == 'text/plain'): print "#0" message_body = part['body'] for header in part['headers']: if header['name'] == 'Content-Type': charset = header['value'].rpartition('charset=')[2] charset = re.sub('"', '', charset, flags=re.DOTALL) if header['name'] == 'Content-Transfer-Encoding': transferencoding = header['value'] if 'parts' in part: print "#1" for part in part['parts']: if (part['mimeType'] == 'text/html') or (part['mimeType'] == 'text/plain'): message_body = part['body'] for header in part['headers']: if header['name'] == 'Content-Type': charset = header['value'].rpartition('charset=')[2] charset = re.sub('"', '', charset, flags=re.DOTALL) if header['name'] == 'Content-Transfer-Encoding': transferencoding = header['value'] msg_str = base64.urlsafe_b64decode((message_body['data']).encode('ascii')) # msg_str = msg_str.decode(charset) # msg_str = msg_str.encode('utf-8') else: message_body = message_payload['body'] print "#3" for header in message_payload['headers']: if header['name'] == 'Content-Type': charset = header['value'].rpartition('charset=')[2] charset = re.sub('"', '', charset, flags=re.DOTALL) msg_str = base64.urlsafe_b64decode((message_body['data']).encode('ascii')) # msg_str = msg_str.encode('utf-8') msg_str = '<pre>' + msg_str + '</pre>' #print transferencoding #if transferencoding == 'quoted-printable': # print "YEEEEEEEEP" # msg_str = quopri.decodestring(msg_str) #if charset != 'UTF-8': #print charset #msg_str = msg_str.decode(charset, errors='ignore') msg_str = unicode(msg_str) msg_str = fix_bad_unicode(msg_str) #msg_str = msg_str.encode('utf-8', errors='ignore') #msg_str = msg_str.decode(charset) #msg_str = msg_str.encode('utf-8') #if charset.lower() is not 'utf-8': msg_str = re.sub('!important', '', msg_str, flags=re.DOTALL) try: transformed_msg = inline_css(msg_str) except: transformed_msg = msg_str #FIX mig clean_msg = re.sub('<html>', '', transformed_msg, flags=re.DOTALL) clean_msg = re.sub('</html>', '', clean_msg, flags=re.DOTALL) clean_msg = re.sub('<head>.*?</head>', '', clean_msg, flags=re.DOTALL) clean_msg = re.sub('<head>.*?</head>', '', clean_msg, flags=re.DOTALL) clean_msg = clean_msg.replace('body', 'div', 1) clean_msg = re.sub('<body>', '', clean_msg, flags=re.DOTALL) clean_msg = re.sub('</body>', '', clean_msg, flags=re.DOTALL) clean_msg = re.sub('<style type="text/css">.*?</style>', '', clean_msg, flags=re.DOTALL) clean_msg = re.sub('<style type="text/css">.*?</style>', '', clean_msg, flags=re.DOTALL) return clean_msg except errors.HttpError, error: # return message print 'An error occurred: %s' % error
def send_mail(template_prefix, from_email, recipient_list, template_context, request=None, fail_silently=False, **kwargs): # Sends a templated HTML email. # # Unrecognized arguments are passed on to Django's EmailMultiAlternatives's init method. # add default template context variables from settings.DEFAULT_TEMPLATE_CONTEXT template_context = build_template_context(template_context) # subject subject = render_to_string(template_prefix + '_subject.txt', template_context, request=request) subject = re.sub(r"\s*[\n\r]+\s*", " ", subject).strip( ) # remove superfluous internal white space around line breaks and leading/trailing spaces # Add subject as a new context variable, and it is used in the base HTML template's title tag. template_context['subject'] = subject # body # see if a Markdown template is present try: # Use the template engine's loaders to find the template, but then just # ask for its source so we have the raw Markdown. md_template = Engine.get_default().get_template(template_prefix + '.md').source except TemplateDoesNotExist: md_template = None if md_template: # render the text and HTML parts from the Markdown template text_body, html_body = render_from_markdown(md_template, template_context) else: # render from separate text and html templates text_body = render_to_string(template_prefix + '.txt', template_context, request=request) html_body = render_to_string(template_prefix + '.html', template_context, request=request) # inline HTML styles because some mail clients dont process the <style> tag html_body = inline_css(html_body) # construct MIME message msg = EmailMultiAlternatives(subject=subject, body=text_body, from_email=from_email, to=recipient_list, **kwargs) msg.attach_alternative(html_body, "text/html") # send! msg.send(fail_silently=fail_silently)
def render_template(kwargs, template_name='email.html'): template_floder = '/Users/cyang1/code/Innovation/backend/myapp/tpl/' env = Environment(loader=FileSystemLoader(template_floder)) html = env.get_template(template_name).render(**kwargs) html_with_css = inline_css(html) return html_with_css
def test_no_markup(): inlined = inline_css("Hello World!") expected = u'<html>\n <body>\n <p>Hello World!</p>\n </body>\n</html>\n' assert expected == inlined
def render_to_mail(name, context): if not context.get("request"): context["request"] = get_request() # if not isinstance(context, RequestContext): # tmp = RequestContext(context.get('request', None)) # tmp.update(context) # context = tmp context['newline'] = "\n" # print "TEMPLATE NAME: {0}".format(name) if 'to' in context: toaddrs = context['to'] if type(toaddrs) != list: toaddrs = [toaddrs] else: try: toaddrs = render_to_string(name + ".to", context).splitlines() except TemplateDoesNotExist as err: return try: while True: toaddrs.remove('') except ValueError: pass if len(toaddrs) == 0: logging.getLogger("app").error("Sending email to no one: %s" % name) return try: html_content = render_to_string(name + ".html", context) html_content = inline_css(html_content) except TemplateDoesNotExist as err: html_content = None pass text_content = "" try: text_content = render_to_string(name + ".txt", context) except TemplateDoesNotExist as error: if html_content == None: raise TemplateDoesNotExist( "requires at least one content template") if 'from' in context: fromaddr = context['from'] else: try: fromaddr = render_to_string(name + ".from", context).rstrip() except TemplateDoesNotExist: fromaddr = settings.DEFAULT_FROM_EMAIL # print fromaddr if 'subject' in context: subject = context['subject'] else: try: subject = render_to_string(name + ".subject", context).rstrip() except TemplateDoesNotExist: logging.getLogger("app").error( "Sending email without subject: %s" % name) return False headers = None if "replyto" in context: headers = {'Reply-To': context["replyto"]} email = EmailMultiAlternatives(subject, text_content, fromaddr, toaddrs, headers=headers) if html_content: email.attach_alternative(html_content, "text/html") print "sending email to: {0} - {1}".format(toaddrs, subject) logging.getLogger("debug").info("sending email to: {0} - {1}".format( toaddrs, subject)) #try: t = threading.Thread(target=async_send, args=[email]) t.start()
Otherwise, you can probably ignore the --install-dir flag. PS: Normally I avoid easy_install and related tools, but lxml is actually a good package and won't destroy the world. """ import os import sys sys.path.insert(0, 'cssutils/src') sys.path.insert(0, 'inlinestyler') from inlinestyler.utils import inline_css TEMPLATES_PATH = '../frontend/templates/' for input_name in os.listdir(TEMPLATES_PATH): if not input_name.endswith('email_input.html'): continue input_path = os.path.join(TEMPLATES_PATH, input_name) output_path = input_path.replace('email_input.html', 'email_output.html') print 'Processing %s into %s' % (input_path, output_path) input_template = open(input_path).read() output_data = inline_css(input_template) open(output_path, 'w').write(output_data)
def generate_email_bodies(self, vacancies, new_vacancies): html_vacancies = E('div') html = E('html', E('head', E('style', self.html_css, type='text/css')), E('body', self.html_preamble, html_vacancies)) text_body = [self.text_preamble] if len(vacancies.xpath('/vacancies/vacancy')) == 0: raise SystemExit(0) for i, vacancy in enumerate(vacancies.xpath('/vacancies/vacancy')): vacancy_id = vacancy.attrib['id'] html_description = etree.fromstring( vacancy.xpath("description[@media_type='text/html']")[0].text, parser=etree.HTMLParser())[0][0] first_para = html_description.xpath( ".//text()[normalize-space(.) and not(contains(., 'INTERNAL') or contains(., 'ADVERTISEMENT'))]" )[0].strip() html_first_para = E('div', first_para, **{'class': 'description'}) tags = [] if 'INTERNAL' in html_description.text: tags.append('internal applicants only') if 'ADVERTISEMENT' in html_description.text: tags.append('re-advertisement') tags = ' ({0})'.format(', '.join(tags)) if tags else '' try: closes = dateutil.parser.parse(vacancy.find('closes').text) except Exception: closes, closes_soon = 'unknown', False else: closes_soon = (closes - datetime.datetime.now( pytz.utc)).total_seconds() < 3600 * 24 * 2 closes = closes.strftime('%a, %d %b %Y, %I:%M %p') html_vacancy = E( 'div', E('h1', vacancy.find('label').text), E( 'div', E('span', vacancy.find('salary').find('label').text, **{'class': 'salary'}), '; closes: ', E( 'span', closes, **{ 'class': 'closes' + (' closes-soon' if closes_soon else '') }), tags, **{'class': 'byline'}), html_first_para, E( 'div', E('a', 'More details\N{HORIZONTAL ELLIPSIS}', href=vacancy.find('webpage').text)), **{'class': 'vacancy'}) if vacancy_id in new_vacancies: html_vacancy[0].text += " " html_vacancy[0].append( E('span', '\N{BLACK STAR} new', **{'class': 'new'})) html_vacancies.append(html_vacancy) text_body.extend([ '_' * 70, '\n\n', textwrap.fill(vacancy.find('label').text), ' *NEW*' if vacancy_id in new_vacancies else '', '\n\n', vacancy.find('salary').find('label').text, '\nCloses: ', closes, tags, '\n\n', textwrap.fill(first_para), '\n\n' 'More details: https://data.ox.ac.uk/v/', vacancy.attrib['id'], '\n' ]) html_body = inline_css(etree.tostring(html, method='html')) text_body = ''.join(text_body).encode('utf-8') return html_body, text_body
from inlinestyler.utils import inline_css import os import sys file = sys.argv[-1] htmlFile = open(file, "r") message_inline_css = inline_css(htmlFile.read()) htmlFile.close() outputHtml = "inlined/inlined-" + os.path.basename(file) outputFile = open(outputHtml, "w") outputFile.write(message_inline_css) outputFile.close()
def test_respects_encoding_argument(): inlined = inline_css("Hello World!", encoding='utf-16') expected = '<html><body><p>Hello World!</p></body></html>\n'.encode( 'utf-16') assert expected == inlined
def mail_send_task( self, to: list, subject: str, body: str, html: str, reply_to: list = None, event: int = None, cc: list = None, bcc: list = None, headers: dict = None, ): reply_to = ([] if not reply_to or (len(reply_to) == 1 and reply_to[0] == "") else reply_to) reply_to = reply_to.split(",") if isinstance(reply_to, str) else reply_to if isinstance(to, str): to = [to] if event: event = Event.objects.get(pk=event) backend = event.get_mail_backend() sender = settings.MAIL_FROM if event.settings.smtp_use_custom: sender = event.settings.mail_from or sender reply_to = reply_to or event.settings.mail_reply_to if not reply_to and sender == settings.MAIL_FROM: reply_to = event.email if isinstance(reply_to, str): reply_to = [formataddr((str(event.name), reply_to))] sender = formataddr((str(event.name), sender or settings.MAIL_FROM)) else: sender = formataddr(("pretalx", settings.MAIL_FROM)) backend = get_connection(fail_silently=False) email = EmailMultiAlternatives( subject, body, sender, to=to, cc=cc, bcc=bcc, headers=headers or {}, reply_to=reply_to, ) if html is not None: from inlinestyler.utils import inline_css email.attach_alternative(inline_css(html), "text/html") try: backend.send_messages([email]) except SMTPResponseException as exception: # pragma: no cover # Retry on external problems: Connection issues (101, 111), timeouts (421), filled-up mailboxes (422), # out of memory (431), network issues (442), another timeout (447), or too many mails sent (452) if exception.smtp_code in (101, 111, 421, 422, 431, 442, 447, 452): self.retry(max_retries=5, countdown=2**(self.request.retries * 2)) logger.exception("Error sending email") raise SendMailException("Failed to send an email to {}: {}".format( to, exception)) except Exception as exception: # pragma: no cover logger.exception("Error sending email") raise SendMailException("Failed to send an email to {}: {}".format( to, exception))
def format_html_email(markdown_text, subject): markdown_html = Markup(markdown.markdown(markdown_text)) return inline_css( render_template('admin/email/email_template.html', subject=subject, content=markdown_html))
def test_non_utf8_encoding_adds_headers(): inlined = inline_css("Hello World!", encoding='utf-16') expected = u"<?xml version='1.0' encoding='utf-16'?>\n<html>\n <body>\n <p>Hello World!</p>\n </body>\n</html>\n" assert expected == inlined
from_email=settings.DEFAULT_FROM_EMAIL, fail_silently=True, template=None, context=None, async=False): if type(to) not in (tuple, list): to = [to] if template and body and not context: context = {"body": body} if template and context: if type(context) is dict: context['settings'] = settings body = render_to_string(template, context) body = inline_css(body) msg = EmailMessage(subject=subject, body=body, from_email=from_email, to=to) msg.content_subtype = "html" for a in attachments: if type(a) in [str, unicode]: msg.attach_file(a) else: msg.attach(a.name, a.data, a.mimetype) if async: t = threading.Thread(target=async_send, args=[msg]) t.start()
def generate_email_bodies(self, vacancies, new_vacancies): html_vacancies = E('div') html = E('html', E('head', E('style', self.html_css, type='text/css')), E('body', self.html_preamble, html_vacancies)) text_body = [self.text_preamble] if len(vacancies.xpath('/vacancies/vacancy')) == 0: raise SystemExit(0) for i, vacancy in enumerate(vacancies.xpath('/vacancies/vacancy')): vacancy_id = vacancy.attrib['id'] html_description = etree.fromstring(vacancy.xpath("description[@media_type='text/html']")[0].text, parser=etree.HTMLParser())[0][0] first_para = html_description.xpath(".//text()[normalize-space(.) and not(contains(., 'INTERNAL') or contains(., 'ADVERTISEMENT'))]")[0].strip() html_first_para = E('div', first_para, **{'class': 'description'}) tags = [] if 'INTERNAL' in html_description.text: tags.append('internal applicants only') if 'ADVERTISEMENT' in html_description.text: tags.append('re-advertisement') tags = ' ({0})'.format(', '.join(tags)) if tags else '' try: closes = dateutil.parser.parse(vacancy.find('closes').text) except Exception: closes, closes_soon = 'unknown', False else: closes_soon = (closes - datetime.datetime.now(pytz.utc)).total_seconds() < 3600 * 24 * 2 closes = closes.strftime('%a, %d %b %Y, %I:%M %p') html_vacancy = E('div', E('h1', vacancy.find('label').text), E('div', E('span', vacancy.find('salary').find('label').text, **{'class': 'salary'}), '; closes: ', E('span', closes, **{'class': 'closes' + (' closes-soon' if closes_soon else '')}), tags, **{'class': 'byline'} ), html_first_para, E('div', E('a', 'More details\N{HORIZONTAL ELLIPSIS}', href=vacancy.find('webpage').text)), **{'class': 'vacancy'} ) if vacancy_id in new_vacancies: html_vacancy[0].text += " " html_vacancy[0].append(E('span', '\N{BLACK STAR} new', **{'class': 'new'})) html_vacancies.append(html_vacancy) text_body.extend([ '_' * 70, '\n\n', textwrap.fill(vacancy.find('label').text), ' *NEW*' if vacancy_id in new_vacancies else '', '\n\n', vacancy.find('salary').find('label').text, '\nCloses: ', closes, tags, '\n\n', textwrap.fill(first_para), '\n\n' 'More details: https://data.ox.ac.uk/v/', vacancy.attrib['id'], '\n' ]) html_body = inline_css(etree.tostring(html, method='html')) text_body = ''.join(text_body).encode('utf-8') return html_body, text_body
for name, config in Config.PROJECTS.iteritems(): if not name in args.projects: continue # init newrelic newrelic = NewRelic(config['NR_ACCOUNT_ID']) newrelic.login(config['NR_LOGIN_EMAIL'], config['NR_LOGIN_PASSWORD']) # load data serverssum = newrelic.get_servers_overview() appssum = newrelic.get_apps_overview() errors = newrelic.get_errors(config['NR_ERROR_REPORT_FOR_APPS'], args.hours) # render email template = env.get_template('index.html') html = template.render(name=name, config=config, hours=args.hours, appssum=appssum, serverssum=serverssum, errors=errors) html = inline_css(html.encode('utf-8')) # send email msg = MIMEText(html, 'html', 'utf-8') msg['Subject'] = '%s NewRelic Summary Report' % name.capitalize() msg['From'] = config['EMAIL_FROM'] msg['To'] = ', '.join(config['EMAIL_TO']) if args.p: print html else: p = Popen(['/usr/sbin/sendmail', '-t'], stdin=PIPE) p.communicate(msg.as_string())
def format_html_email(markdown_text, subject): markdown_html = Markup(markdown.markdown(markdown_text)) return inline_css(render_template('admin/email/email_template.html', subject=subject, content=markdown_html))
def render(self, name, embed, subscriptions_url): # Render email, set embed=True for sending mail, or embed=False for viewing in browser # Notes: # absolute_uri = '%s://%s' % (request.scheme, request.get_host()) # subscriptions_url = request.build_absolute_uri(reverse('hemres.views.view_home')) context = {} context['render_mail'] = embed context['subscriptions_url'] = subscriptions_url context['attachments'] = {} # receives MIME attachments allowed_tags = ['a', 'b', 'blockquote', 'caption', 'code', 'em', 'h1', 'h2', 'h3', 'hr', 'i', 'img', 'strong', 'ul', 'ol', 'li', 'p', 'br', 'span', 'table', 'tbody', 'tr', 'td', 'thead', 'div', 'span'] allowed_attrs = { '*': ['class', 'style'], 'a': ['href', 'target'], 'img': ['src', 'alt', 'width', 'height'], 'table': ['border', 'align', 'cellpadding', 'cellspacing'], } allowed_protocols = ['http', 'https', 'mailto', 'cid'] class AllowAllStyles(object): def __contains__(self, value): return True allowed_styles = AllowAllStyles() context['subject'] = mark_safe(bleach.clean(self.subject, tags=allowed_tags, attributes=allowed_attrs)) context['name'] = mark_safe(bleach.clean(name)) context['naam'] = mark_safe(bleach.clean(name)) # first render content then use bleach to restrict HTML # in the template, the following context variables are defined: # - render_mail: Boolean, True if rendering for mail, False if for browser # - subscriptions_url: URL for managing subscriptions # - subject: subject as set in Newsletter object # - name: name of the recipient (as set in EmailSubscriber or in LDAP) # - content: content after rendering header = "{% load hemres_email %}{% limit_filters %}{% limit_tags emailimage_media emailimage_static %}" template = header + self.content template = re.sub('src="{}([^"]*)"'.format(settings.MEDIA_URL), 'src="{% emailimage_media \'\\1\' %}"', template) template = re.sub('src="{}([^"]*)"'.format(settings.STATIC_URL), 'src="{% emailimage_static \'\\1\' %}"', template) context['content'] = Template(template).render(Context(context)) context['content'] = mark_safe(bleach.clean(context['content'], tags=allowed_tags, attributes=allowed_attrs, protocols=allowed_protocols, styles=allowed_styles)) # then render whole mail header = "{% load hemres_email %}{% limit_filters %}{% limit_tags emailimage_media emailimage_static if endif %}" template = header + self.template template = re.sub('src="{}([^"]*)"'.format(settings.MEDIA_URL), 'src="{% emailimage_media \'\\1\' %}"', template) template = re.sub('src="{}([^"]*)"'.format(settings.STATIC_URL), 'src="{% emailimage_static \'\\1\' %}"', template) result = Template(template).render(Context(context)) from inlinestyler.utils import inline_css from lxml.etree import XMLSyntaxError try: result = inline_css(result) except XMLSyntaxError: pass # bad luck # and return the result and all attachments (images) attachments = [mime for mime, cid in list(context['attachments'].values())] return result, attachments
def wrapper(*args, **kwargs): return inline_css(html_renderer_function(*args, **kwargs))
def test_no_markup(): inlined = inline_css("Hello World!") expected = '<html><body><p>Hello World!</p></body></html>\n' assert expected == inlined
def test_respects_encoding_argument(): inlined = inline_css("Hello World!", encoding='utf-16') expected = '<html><body><p>Hello World!</p></body></html>\n'.encode('utf-16') assert expected == inlined