def render(profile, clear=True): """ Render notification email for given profile; return (subject, text, html). If ``clear`` is set to ``False``, will not clear rendered notifications. Raise ``NothingToDo`` if there are no notifications to render. """ collection = collect.NotificationCollection(profile, clear=clear) # bail out if there's nothing to do if not collection: raise NothingToDo() context = collection.context context['BASE_URL'] = settings.PORTFOLIYO_BASE_URL subject = render_to_string(collection.get_subject_template(), context) text = consecutive_newlines.sub('\n\n', render_to_string(TEXT_TEMPLATE, context)) html = premailer.Premailer( render_to_string(HTML_TEMPLATE, context), base_url=settings.PORTFOLIYO_BASE_URL, output_xhtml=True, ).transform() return subject, text, html
def render_to_response(self, context, **response_kwargs): from django.contrib.staticfiles.storage import staticfiles_storage css = staticfiles_storage.path('css/email.css') response = super(EventAuthoriseRequestEmailPreview, self).render_to_response(context, **response_kwargs) assert isinstance(response, HttpResponse) response.content = premailer.Premailer( response.rendered_content, external_styles=css).transform() return response
def to_email(self, *args, **kwargs): """Export a bulletin as an HTML file for emailing.""" request = kwargs.get('request', None) template_string = render_to_string( "bulletins/bulletin_html_email.html", self.get_context(request)) prepared_resp = premailer.Premailer( template_string, base_url=settings.BASE_URL, remove_classes=True, strip_important=True, cssutils_logging_level=logging.CRITICAL).transform() return prepared_resp
def apply_css(self, text): """Bake CSS rules into text""" p = premailer.Premailer(html=text, css_text=self.css, remove_classes=True, remove_unset_properties=True, disable_leftover_css=True) out = p.transform() for tag in ['html', 'head', 'body']: out = out.replace('<%s>' % tag, '') out = out.replace('</%s>' % tag, '') return out
def markdown2html(self, markdown_str): if not isinstance(markdown_str, unicode): log.error('String is not unicode in markdown2html') return '' html = u'<style>' + self.css_str html += '.markdown-body {box-sizing: border-box;min-width: ' \ '200px;max-width: 980px;margin: 0 auto;padding: 45px;}' html += '</style>' html += '<article class="markdown-body">' md_html = markdown2.markdown( markdown_str, extras=["tables", "fenced-code-blocks", "cuddled-lists"]) html += md_html html += '</article>' if log.isEnabledFor(logging.DEBUG): pre_html_file_path = os.path.join( self.html_log_path, str(time.time()).replace('.', '') + '-pre_inline.html') with open(pre_html_file_path, 'w') as f: f.write(html.encode('utf-8-sig')) log.debug('Dump html file ' + pre_html_file_path) prem = premailer.Premailer(html, preserve_inline_attachments=False, base_path='article') html = prem.transform(pretty_print=True) if log.isEnabledFor(logging.DEBUG): html_file_path = os.path.join( self.html_log_path, str(time.time()).replace('.', '') + '-inline.html') with open(html_file_path, 'w') as f: f.write(html.encode('utf-8-sig')) log.debug('Dump inlined html file ' + html_file_path) html = html[html.find('<article'):] html = html[html.find('>') + 1:] html = html[:html.find('</article>')] if log.isEnabledFor(logging.DEBUG): cut_html_file_path = os.path.join( self.html_log_path, str(time.time()).replace('.', '') + '-cut_inline.html') with open(cut_html_file_path, 'w') as f: f.write(html.encode('utf-8-sig')) log.debug('Dump cutted inlined html file ' + cut_html_file_path) log.debug("inline css over") return html
def transform_html(self, html): kwargs = { "html": html, "base_url": "https://glowstone.net" } p = premailer.Premailer( **kwargs ) transformed = p.transform(pretty_print=False) transformed = transformed.replace("%24%7B", "${") return transformed.replace("%7D", "}")
def parse(html): soup = BeautifulSoup(html, 'html.parser') head = soup.find('head') table = soup.find('div', {"class": "Search-list"}) result_html = premailer.Premailer('<html>' + str(head) + '<body>' + str(table) + '</body></html>', cssutils_logging_level=logging.CRITICAL, base_url='https://www.fabrikant.ru/').transform() with open('result.html', 'w') as f_obj_out: f_obj_out.write(result_html) #print(table) send_mail()
def from_template(cls, email_name, context, *, request): subject = render(f"email/{email_name}/subject.txt", context, request=request) body_text = render(f"email/{email_name}/body.txt", context, request=request) try: body_html = render( f"email/{email_name}/body.html", context, request=request ) body_html = premailer.Premailer(body_html, remove_classes=True).transform() # Catching TemplateNotFound here is a bit of a leaky abstraction, but there's # not much we can do about it. except TemplateNotFound: body_html = None return cls(subject=subject, body_text=body_text, body_html=body_html)
def render(self): tpl = loader.get_template(self.template) context = self._default_context if getattr(settings, "TEMPLATE_EMAIL_USE_CONTEXT_PROCESSORS", False): if Engine: standard_processors = Engine.get_default().template_context_processors else: standard_processors = get_standard_processors() for processor in standard_processors: try: context.update(processor(None)) except: pass context.update(self.context) context.update(self._override_context) context_subject = dict(context, _subject=True) context_body = dict(context, _body=True) context_html = dict(context, _bodyhtml=True) subject = tpl.render(Context(context_subject)).strip() body = tpl.render(Context(context_body)).strip() html = tpl.render(Context(context_html)).strip() if subject != '': self.subject = subject if body != '': self.body = body if html != '': html_doc = None base_url = getattr(settings, "TEMPLATE_EMAIL_BASE_URL", None) if base_url: html_doc = html_doc or lxml.html.fromstring(html) html_doc.make_links_absolute(base_url) if getattr(settings, "TEMPLATE_EMAIL_INLINE_CSS", False): html_doc = html_doc or lxml.html.fromstring(html) opts = getattr( settings, "TEMPLATE_EMAIL_INLINE_CSS_OPTIONS", {}) html_doc = premailer.Premailer(html_doc, **opts).transform() if html_doc: html = lxml.html.tostring( html_doc, include_meta_content_type=True).decode('utf-8') self.html = html self._rendered = True
def prepare_email_body(context, css, template, title): #: Before template is rendered, we verify that its content is secure env = SandboxedEnvironment() body = env.from_string(template).render(context) mylog = StringIO() myhandler = logging.StreamHandler(mylog) html_message = EMAIL_HTML_SQUELETON.format(title=title, css=css, body=body) p = premailer.Premailer( html=html_message, cssutils_logging_handler=myhandler, cssutils_logging_level=logging.INFO, ) return p.transform()
def report_to_html(report): template = report.get_template() report_env = report.environment() report_env[ 'EML_RENDER'] = True # for exclude scripts and css-styles from message body html_text = template.render(**report_env) premailer_log = StringIO() premailer_log_handler = logging.StreamHandler(premailer_log) return premailer.Premailer( cssutils_logging_handler=premailer_log_handler, cssutils_logging_level=logging.CRITICAL, remove_classes=True, base_url=KeyChain.WEB_PATH, base_path=WEB_STATIC_PATH, external_styles=f'css/bootstrap.css', ).transform(html_text)
def send_email(title, html_text, body_text, recipients): # Prepare email css = sass.compile(string=flask.render_template('email/base.scss')) html = flask.render_template('email/base.html', title=title, css=css, text=html_text) html = premailer.Premailer(html, strip_important=False).transform() body = flask.render_template('email/base.txt', title=title, text=body_text) # Send email mail = flask_mail.Mail(flask.current_app) msg = flask_mail.Message(title, recipients=recipients, body=body, html=html) mail.send(msg)
def form_valid(self, form): email = form.cleaned_data['email'] event = self.object event.auth_request_by = self.request.user event.auth_request_at = datetime.datetime.now() event.auth_request_to = email event.save() context = { 'object': self.object, 'request': self.request, 'hmac': signing.dumps({ 'pk': self.object.pk, 'email': email, 'sent_by': self.request.user.pk, }), } if event.person is not None and email == event.person.email: context['to_name'] = event.person.name elif event.organisation is not None and email == event.organisation.email: context['to_name'] = event.organisation.name msg = EmailMultiAlternatives( "N%05d | %s - Event Authorisation Request" % (self.object.pk, self.object.name), get_template("RIGS/eventauthorisation_client_request.txt").render( context), to=[email], reply_to=[self.request.user.email], ) css = staticfiles_storage.path('css/email.css') html = premailer.Premailer(get_template( "RIGS/eventauthorisation_client_request.html").render(context), external_styles=css).transform() msg.attach_alternative(html, 'text/html') msg.send() return super(EventAuthorisationRequest, self).form_valid(form)
def premailer_transform(html): p = premailer.Premailer(html, base_url='https://downtownstimulus.com/') return p.transform()
#!/bin/python3 import premailer, json, os, pathlib REPO_PATH = pathlib.Path(os.environ['GITHUB_WORKSPACE']) FILES_LIST = json.loads(os.environ['INPUT_FILES']) pm = premailer.Premailer() for file_path_str in FILES_LIST: file_path_list = REPO_PATH.glob(file_path_str) for file_path in file_path_list: with open(file_path, 'r') as file: html = pm.transform(file.read()) with open(file_path, 'w') as file: file.write(html)
def send_email_back(recipient, subject, attachments, text_content=None, html_content=None): from sendgrid.helpers import mail from sendgrid.helpers.mail import Attachment import premailer logging.info("sending mail to %s (%s/%s)", recipient, SENDGRID_API_KEY, SENDGRID_SENDER) to_email = mail.Email(recipient) from_email = mail.Email(SENDGRID_SENDER) message = mail.Mail() message.set_from(from_email) message.set_subject(subject) personalization = mail.Personalization() personalization.add_to(to_email) message.add_personalization(personalization) if not text_content and not html_content: message.add_content(mail.Content("text/plain", global_body)) if text_content: message.add_content(mail.Content("text/plain", text_content)) if html_content: message.add_content(mail.Content("text/html", html_content)) for att in attachments: data = att["data"] file_name = att["name"] if file_name.endswith(".htm") or file_name.endswith(".html"): stub_css = "https://%s.appspot.com/css/stub.css" % app_identity.get_application_id() data = re.sub( r'\"D:\\ssis\\SecureMail\\SecureMailTest\\MailItemImages\\BankB1\.gifstyle\.css
.*\"', '"%s"' % stub_css, data) logging.info("before transform(%s) %s", type(data), data) logging.info("using premailer for %s", file_name) data = data.decode("utf8") p = premailer.Premailer(data) data = p.transform().encode("utf8") logging.info("after transform(%s) %s", type(data), data) attachment = Attachment() attachment.set_content(base64.b64encode(data)) attachment.set_type(att["type"]) attachment.set_filename(att["name"]) attachment.set_disposition("attachment") attachment.set_content_id(att["name"]) message.add_attachment(attachment) data = json.dumps(message.get()) logging.debug("sending %s", data) headers = { "Authorization": 'Bearer {0}'.format(SENDGRID_API_KEY), "Content-Type": "application/json", "Accept": 'application/json' } response = urlfetch.fetch( url="https://api.sendgrid.com/v3/mail/send", payload=data, method=urlfetch.POST, headers=headers) if response.status_code > 299: logging.error("response %s(%s)", response.content, response.status_code) else: logging.info("response %s(%s)", response.content, response.status_code) if response.status_code > 299: raise Exception("Failed to call sendgrid API")
def do_premailer(value, **kwargs): p = premailer.Premailer(value, keep_style_tags=kwargs.get('keep_style_tags', True), remove_classes=kwargs.get('remove_classes', True)) return p.transform()
def premailer_transform(html): p = premailer.Premailer(html, base_url=os.environ.get('FRONTEND_URL', 'NO ENV FOUND')) return p.transform()
def prepare_html(html, inline_css=True): if inline_css: html = premailer.Premailer(html).transform() return html
def transformExternalCssToInline(code): import premailer p = premailer.Premailer(code, strip_important=False, keep_style_tags=True, remove_classes=False) return p.transform()
import logging import premailer from io import StringIO mylog = StringIO() myhandler = logging.StreamHandler(mylog) p = premailer.Premailer(""" <html> <style type="text/css"> @keyframes foo { from { opacity: 0; } to { opacity: 1; } } </style> <p>Hej</p> </html>""", cssutils_logging_handler=myhandler, cssutils_logging_level=logging.INFO) result = p.transform() mylog.getvalue()
# FILENAME: css_inliner_tool.py # DESCRIPTION: Retrieves an HTML file from a URL and outputs a new # HTML file that inlines all of its CSS. # # # $Id$ #################################################################### # (C)2017 DigiTar, All Rights Reserved #################################################################### import premailer, requests from argparse import ArgumentParser parser = ArgumentParser() parser.add_argument("--page_url", dest="page_url", required=True) if __name__ == "__main__": args = parser.parse_args() # Retrieve Main Page html_text = requests.get(args.page_url).text # Transform HTML html_inliner = premailer.Premailer(html_text, strip_important=False, remove_classes=True, remove_unset_properties=True) inlined_html = html_inliner.transform() print inlined_html.encode("utf-8")
def generate(trello_list): articles = [] pool = multiprocessing.Pool(processes=10) articles = pool.map(get_artice, trello_list) # Print status for number, (trello_card, article) in enumerate(zip(trello_list, articles), start=1): print("\n" + str(number) + ".", trello_card["name"] + ":") if article is None: print(" - Status:", colorama.Fore.RED + "Warning (no content)", colorama.Fore.RESET) continue images_str = ", ".join(map(lambda x: x["name"], article["images"])) print(" - Images:", colorama.Fore.CYAN + images_str, colorama.Fore.RESET) labels_str = ", ".join(article["labels"]) print(" - Labels:", colorama.Fore.MAGENTA + labels_str, colorama.Fore.RESET) print(" - Status:", colorama.Fore.GREEN + "Ok", colorama.Fore.RESET) # Remove empty articles articles = list(filter(None, articles)) # Create output folder if not os.path.exists(settings.get("folder")): os.makedirs(settings.get("folder")) # Generate html from articles html_section_template = Template( open(settings.get("template-section")).read()) markdown_instance = markdown.Markdown( extensions=list(settings.get("extensions")), extension_configs=settings.get("extensions"), output_format="html5") html = "" for index, article in enumerate(articles): labels = "" if settings.get("features")["labels"]: labels = " ".join(article["labels"]) open( os.path.join(settings.get("folder"), ".t2w-temp-" + str(index) + ".md"), "w").write(article["content"]) article_html = markdown_instance.reset().convert(article["content"]) html += html_section_template.substitute(content=article_html, labels=labels) if settings.get("features")["lines"] and "noline" not in article[ "labels"] and index != len(articles) - 1: line_html = markdown_instance.reset().convert("\n\n---\n\n") html += html_section_template.substitute(content=line_html, labels="") # Save images for article in articles: for image in article["images"]: image_filename = os.path.join(settings.get("folder"), image["name"]) open(image_filename, "wb").write(image["content"]) utilities.fix_image(image_filename, settings.get("features")["width"]) # Generate CSS css_generated = "" for css_file in settings.get("css"): css_generated += open(css_file).read() + "\n\n" # Add generated Markdown to HTML template html_template = Template(open(settings.get("template")).read()) html_generated = html_template.safe_substitute(title=settings.get("title"), content=html, css=css_generated) result_template = Template(html_generated) extra_args = {} if "markdown_smarttoc" in settings.get("extensions"): extra_args["toc"] = markdown_instance.toc result_generated = result_template.safe_substitute( title=settings.get("title"), width=settings.get("features")["width"], **extra_args) # Run premailer if settings.get("features")["premailer"]: open( os.path.join( settings.get("folder"), ".t2w-temp-" + settings.get("basename") + "-orignal.html"), "w").write(result_generated) premail_instance = premailer.Premailer(result_generated, keep_style_tags=True) result_generated = premail_instance.transform() open( os.path.join(settings.get("folder"), settings.get("basename") + ".html"), "w").write(result_generated) print("\nPreview: file://" + urllib.request.pathname2url( os.path.abspath( os.path.join(settings.get("folder"), settings.get("basename") + ".html"))))
def premailer_transform(html): cssutils.log.setLevel(logging.CRITICAL) p = premailer.Premailer(html, base_url=settings.BASE_URL) return p.transform()
def on_post(self, req, resp): # req.stream corresponds to the WSGI wsgi.input environ variable, # and allows you to read bytes from the request body. # # See also: PEP 3333 if req.content_length in (None, 0): # Nothing to do return body = req.stream.read() if not body: raise falcon.HTTPBadRequest('Empty request body', 'A valid JSON document is required.') body = json.loads(body.decode('utf-8')) url = None if body.get('url'): url = body.pop('url') html = self._download_url(url) if 'html' in body: body.pop('html') else: html = body.pop('html') if 'url' in body: body.pop('url') options = body row = insert_post(html, options, url=url, user_agent=req.user_agent) pretty_print = options.pop('pretty_print', True) mylog = StringIO() logging_handler = logging.StreamHandler(mylog) logging_handler.setFormatter( logging.Formatter('%(levelname)s %(message)s')) options['cssutils_logging_handler'] = logging_handler options['cssutils_logging_level'] = logging.WARNING try: p = premailer.Premailer(html, **options) except TypeError as exp: raise falcon.HTTPBadRequest('Invalid options to premailer', str(exp)) error = None warnings = None t0 = time.time() try: result = p.transform(pretty_print=pretty_print) except Exception: exc_type, exc_value, __ = sys.exc_info() error = '{} ({})'.format(exc_type.__name__, exc_value) warnings = mylog.getvalue() t1 = time.time() if error is None: update_post(row, t1 - t0, result=result) else: update_post(row, t1 - t0, error=error) resp.status = falcon.HTTP_200 resp.set_header('Access-Control-Allow-Origin', CORS_ORIGIN) resp.set_header('Content-Type', 'application/json') took = (t1 - t0) * 1000 if error: resp.body = json.dumps({ 'errors': [error], 'took': took, }, indent=2) else: resp.body = json.dumps( { 'html': result, 'took': took, 'warnings': warnings, }, indent=2) # cleaning up del p