##// END OF EJS Templates
emails: added premailer for inline style formatting to make emails render nicer on all email clients.
marcink -
r4275:9be1d088 default
parent child Browse files
Show More
@@ -171,6 +171,17 b' self: super: {'
171 license = [ pkgs.lib.licenses.mit ];
171 license = [ pkgs.lib.licenses.mit ];
172 };
172 };
173 };
173 };
174 "cachetools" = super.buildPythonPackage {
175 name = "cachetools-3.1.1";
176 doCheck = false;
177 src = fetchurl {
178 url = "https://files.pythonhosted.org/packages/ae/37/7fd45996b19200e0cb2027a0b6bef4636951c4ea111bfad36c71287247f6/cachetools-3.1.1.tar.gz";
179 sha256 = "16m69l6n6y1r1y7cklm92rr7v69ldig2n3lbl3j323w5jz7d78lf";
180 };
181 meta = {
182 license = [ pkgs.lib.licenses.mit ];
183 };
184 };
174 "celery" = super.buildPythonPackage {
185 "celery" = super.buildPythonPackage {
175 name = "celery-4.3.0";
186 name = "celery-4.3.0";
176 doCheck = false;
187 doCheck = false;
@@ -372,6 +383,17 b' self: super: {'
372 license = [ pkgs.lib.licenses.bsdOriginal ];
383 license = [ pkgs.lib.licenses.bsdOriginal ];
373 };
384 };
374 };
385 };
386 "cssutils" = super.buildPythonPackage {
387 name = "cssutils-1.0.2";
388 doCheck = false;
389 src = fetchurl {
390 url = "https://files.pythonhosted.org/packages/5c/0b/c5f29d29c037e97043770b5e7c740b6252993e4b57f029b3cd03c78ddfec/cssutils-1.0.2.tar.gz";
391 sha256 = "1bxchrbqzapwijap0yhlxdil1w9bmwvgx77aizlkhc2mcxjg1z52";
392 };
393 meta = {
394 license = [ { fullName = "GNU Library or Lesser General Public License (LGPL)"; } { fullName = "LGPL 2.1 or later, see also http://cthedot.de/cssutils/"; } ];
395 };
396 };
375 "decorator" = super.buildPythonPackage {
397 "decorator" = super.buildPythonPackage {
376 name = "decorator-4.1.2";
398 name = "decorator-4.1.2";
377 doCheck = false;
399 doCheck = false;
@@ -1237,6 +1259,24 b' self: super: {'
1237 license = [ pkgs.lib.licenses.mit ];
1259 license = [ pkgs.lib.licenses.mit ];
1238 };
1260 };
1239 };
1261 };
1262 "premailer" = super.buildPythonPackage {
1263 name = "premailer-3.6.1";
1264 doCheck = false;
1265 propagatedBuildInputs = [
1266 self."lxml"
1267 self."cssselect"
1268 self."cssutils"
1269 self."requests"
1270 self."cachetools"
1271 ];
1272 src = fetchurl {
1273 url = "https://files.pythonhosted.org/packages/62/da/2f43cdf9d3d79c80c4856a12389a1f257d65fe9ccc44bc6b4383c8a18e33/premailer-3.6.1.tar.gz";
1274 sha256 = "08pshx7a110k4ll20x0xhpvyn3kkipkrbgxjjn7ncdxs54ihdhgw";
1275 };
1276 meta = {
1277 license = [ pkgs.lib.licenses.psfl { fullName = "Python"; } ];
1278 };
1279 };
1240 "prompt-toolkit" = super.buildPythonPackage {
1280 "prompt-toolkit" = super.buildPythonPackage {
1241 name = "prompt-toolkit-1.0.18";
1281 name = "prompt-toolkit-1.0.18";
1242 doCheck = false;
1282 doCheck = false;
@@ -1833,6 +1873,7 b' self: super: {'
1833 self."pastedeploy"
1873 self."pastedeploy"
1834 self."pastescript"
1874 self."pastescript"
1835 self."peppercorn"
1875 self."peppercorn"
1876 self."premailer"
1836 self."psutil"
1877 self."psutil"
1837 self."py-bcrypt"
1878 self."py-bcrypt"
1838 self."pycurl"
1879 self."pycurl"
@@ -36,6 +36,7 b' paste==3.4.0'
36 pastedeploy==2.1.0
36 pastedeploy==2.1.0
37 pastescript==3.2.0
37 pastescript==3.2.0
38 peppercorn==0.6
38 peppercorn==0.6
39 premailer==3.6.1
39 psutil==5.7.0
40 psutil==5.7.0
40 py-bcrypt==0.4
41 py-bcrypt==0.4
41 pycurl==7.43.0.3
42 pycurl==7.43.0.3
@@ -49,6 +49,7 b' def send_email(recipients, subject, body'
49 :param subject: subject of the mail
49 :param subject: subject of the mail
50 :param body: body of the mail
50 :param body: body of the mail
51 :param html_body: html version of body
51 :param html_body: html version of body
52 :param email_config: specify custom configuration for mailer
52 """
53 """
53 log = get_logger(send_email)
54 log = get_logger(send_email)
54
55
@@ -26,6 +26,7 b' Model for notifications'
26 import logging
26 import logging
27 import traceback
27 import traceback
28
28
29 import premailer
29 from pyramid.threadlocal import get_current_request
30 from pyramid.threadlocal import get_current_request
30 from sqlalchemy.sql.expression import false, true
31 from sqlalchemy.sql.expression import false, true
31
32
@@ -328,6 +329,12 b' class EmailNotificationModel(BaseModel):'
328 'rhodecode:templates/email_templates/pull_request_update.mako',
329 'rhodecode:templates/email_templates/pull_request_update.mako',
329 }
330 }
330
331
332 premailer_instance = premailer.Premailer(
333 cssutils_logging_level=logging.DEBUG,
334 cssutils_logging_handler=logging.getLogger().handlers[0]
335 if logging.getLogger().handlers else None,
336 )
337
331 def __init__(self):
338 def __init__(self):
332 """
339 """
333 Example usage::
340 Example usage::
@@ -391,4 +398,11 b' class EmailNotificationModel(BaseModel):'
391 # render WHOLE template
398 # render WHOLE template
392 body = email_template.render(None, **_kwargs)
399 body = email_template.render(None, **_kwargs)
393
400
401 try:
402 # Inline CSS styles and conversion
403 body = self.premailer_instance.transform(body)
404 except Exception:
405 log.exception('Failed to parse body with premailer')
406 pass
407
394 return subject, headers, body, body_plaintext
408 return subject, headers, body, body_plaintext
@@ -594,9 +594,21 b' div.annotatediv { margin-left: 2px; marg'
594 .CodeMirror ::-moz-selection { background: @rchighlightblue; }
594 .CodeMirror ::-moz-selection { background: @rchighlightblue; }
595
595
596 .code { display: block; border:0px !important; }
596 .code { display: block; border:0px !important; }
597
597 .code-highlight, /* TODO: dan: merge codehilite into code-highlight */
598 .code-highlight, /* TODO: dan: merge codehilite into code-highlight */
599 .codehilite {
600 /*ElasticMatch is custom RhodeCode TAG*/
601
602 .c-ElasticMatch {
603 background-color: #faffa6;
604 padding: 0.2em;
605 }
606 }
607
598 /* This can be generated with `pygmentize -S default -f html` */
608 /* This can be generated with `pygmentize -S default -f html` */
609 .code-highlight,
599 .codehilite {
610 .codehilite {
611 /*ElasticMatch is custom RhodeCode TAG*/
600 .c-ElasticMatch { background-color: #faffa6; padding: 0.2em;}
612 .c-ElasticMatch { background-color: #faffa6; padding: 0.2em;}
601 .hll { background-color: #ffffcc }
613 .hll { background-color: #ffffcc }
602 .c { color: #408080; font-style: italic } /* Comment */
614 .c { color: #408080; font-style: italic } /* Comment */
@@ -484,21 +484,84 b' text_monospace = "\'Menlo\', \'Liberation M'
484 background-color: #F5F5F5
484 background-color: #F5F5F5
485 }
485 }
486
486
487 /*elasticmatch is custom rhodecode tag*/
488 .codehilite .c-ElasticMatch {
489 background-color: #faffa6;
490 padding: 0.2em;
491 }
492
493 .codehilite .c-ElasticMatch { background-color: #faffa6; padding: 0.2em;}
494 .codehilite .hll { background-color: #ffffcc }
495 .codehilite .c { color: #408080; font-style: italic } /* Comment */
496 .codehilite .err { border: none } /* Error */
497 .codehilite .k { color: #008000; font-weight: bold } /* Keyword */
498 .codehilite .o { color: #666666 } /* Operator */
499 .codehilite .ch { color: #408080; font-style: italic } /* Comment.Hashbang */
500 .codehilite .cm { color: #408080; font-style: italic } /* Comment.Multiline */
501 .codehilite .cp { color: #BC7A00 } /* Comment.Preproc */
502 .codehilite .cpf { color: #408080; font-style: italic } /* Comment.PreprocFile */
503 .codehilite .c1 { color: #408080; font-style: italic } /* Comment.Single */
504 .codehilite .cs { color: #408080; font-style: italic } /* Comment.Special */
505 .codehilite .gd { color: #A00000 } /* Generic.Deleted */
506 .codehilite .ge { font-style: italic } /* Generic.Emph */
507 .codehilite .gr { color: #FF0000 } /* Generic.Error */
508 .codehilite .gh { color: #000080; font-weight: bold } /* Generic.Heading */
509 .codehilite .gi { color: #00A000 } /* Generic.Inserted */
510 .codehilite .go { color: #888888 } /* Generic.Output */
511 .codehilite .gp { color: #000080; font-weight: bold } /* Generic.Prompt */
512 .codehilite .gs { font-weight: bold } /* Generic.Strong */
513 .codehilite .gu { color: #800080; font-weight: bold } /* Generic.Subheading */
514 .codehilite .gt { color: #0044DD } /* Generic.Traceback */
515 .codehilite .kc { color: #008000; font-weight: bold } /* Keyword.Constant */
516 .codehilite .kd { color: #008000; font-weight: bold } /* Keyword.Declaration */
517 .codehilite .kn { color: #008000; font-weight: bold } /* Keyword.Namespace */
518 .codehilite .kp { color: #008000 } /* Keyword.Pseudo */
519 .codehilite .kr { color: #008000; font-weight: bold } /* Keyword.Reserved */
520 .codehilite .kt { color: #B00040 } /* Keyword.Type */
521 .codehilite .m { color: #666666 } /* Literal.Number */
522 .codehilite .s { color: #BA2121 } /* Literal.String */
523 .codehilite .na { color: #7D9029 } /* Name.Attribute */
524 .codehilite .nb { color: #008000 } /* Name.Builtin */
525 .codehilite .nc { color: #0000FF; font-weight: bold } /* Name.Class */
526 .codehilite .no { color: #880000 } /* Name.Constant */
527 .codehilite .nd { color: #AA22FF } /* Name.Decorator */
528 .codehilite .ni { color: #999999; font-weight: bold } /* Name.Entity */
529 .codehilite .ne { color: #D2413A; font-weight: bold } /* Name.Exception */
530 .codehilite .nf { color: #0000FF } /* Name.Function */
531 .codehilite .nl { color: #A0A000 } /* Name.Label */
532 .codehilite .nn { color: #0000FF; font-weight: bold } /* Name.Namespace */
533 .codehilite .nt { color: #008000; font-weight: bold } /* Name.Tag */
534 .codehilite .nv { color: #19177C } /* Name.Variable */
535 .codehilite .ow { color: #AA22FF; font-weight: bold } /* Operator.Word */
536 .codehilite .w { color: #bbbbbb } /* Text.Whitespace */
537 .codehilite .mb { color: #666666 } /* Literal.Number.Bin */
538 .codehilite .mf { color: #666666 } /* Literal.Number.Float */
539 .codehilite .mh { color: #666666 } /* Literal.Number.Hex */
540 .codehilite .mi { color: #666666 } /* Literal.Number.Integer */
541 .codehilite .mo { color: #666666 } /* Literal.Number.Oct */
542 .codehilite .sa { color: #BA2121 } /* Literal.String.Affix */
543 .codehilite .sb { color: #BA2121 } /* Literal.String.Backtick */
544 .codehilite .sc { color: #BA2121 } /* Literal.String.Char */
545 .codehilite .dl { color: #BA2121 } /* Literal.String.Delimiter */
546 .codehilite .sd { color: #BA2121; font-style: italic } /* Literal.String.Doc */
547 .codehilite .s2 { color: #BA2121 } /* Literal.String.Double */
548 .codehilite .se { color: #BB6622; font-weight: bold } /* Literal.String.Escape */
549 .codehilite .sh { color: #BA2121 } /* Literal.String.Heredoc */
550 .codehilite .si { color: #BB6688; font-weight: bold } /* Literal.String.Interpol */
551 .codehilite .sx { color: #008000 } /* Literal.String.Other */
552 .codehilite .sr { color: #BB6688 } /* Literal.String.Regex */
553 .codehilite .s1 { color: #BA2121 } /* Literal.String.Single */
554 .codehilite .ss { color: #19177C } /* Literal.String.Symbol */
555 .codehilite .bp { color: #008000 } /* Name.Builtin.Pseudo */
556 .codehilite .fm { color: #0000FF } /* Name.Function.Magic */
557 .codehilite .vc { color: #19177C } /* Name.Variable.Class */
558 .codehilite .vg { color: #19177C } /* Name.Variable.Global */
559 .codehilite .vi { color: #19177C } /* Name.Variable.Instance */
560 .codehilite .vm { color: #19177C } /* Name.Variable.Magic */
561 .codehilite .il { color: #666666 } /* Literal.Number.Integer.Long */
487
562
488 </style>
563 </style>
489
564
490 <!-- Targeting Windows Mobile -->
491 <!--[if IEMobile 7]>
492 <style type="text/css">
493
494 </style>
495 <![endif]-->
496
497 <!--[if gte mso 9]>
498 <style>
499 /* Target Outlook 2007 and 2010 */
500 </style>
501 <![endif]-->
502 </head>
565 </head>
503 <body>
566 <body>
504
567
General Comments 0
You need to be logged in to leave comments. Login now