Switch from CSS to Table layout for HTML mails so they work in Outlook aka Word

Remove templates-vector and theme templates with variables instead
    Switch to matrix.to URLs by default for links
This commit is contained in:
Matthew Hodgson 2016-05-10 00:14:48 +02:00
parent 6b45ffd2d1
commit 5599608887
13 changed files with 240 additions and 302 deletions

View File

@ -1,115 +0,0 @@
body {
margin: 0px;
}
#page {
font-family: 'Open Sans', Helvetica, Arial, Sans-Serif;
font-size: 12pt;
margin: auto;
max-width: 640px;
padding: 20px;
}
.header {
height: 87px;
border-bottom: 4px solid #e4f7ed;
}
.logo {
float: right;
margin-left: 20px;
}
.salutation {
padding-top: 10px;
font-weight: bold;
}
.summarytext {
}
.room_header {
padding-top: 38px;
padding-bottom: 10px;
border-bottom: 1px solid #e5e5e5;
}
.room_header h2 {
margin-top: 0px;
margin-left: 75px;
font-size: 20px;
}
.room_avatar {
float: left;
margin-top: -8px;
}
.room_avatar img {
width: 48px;
height: 48px;
object-fit: cover;
border-radius: 24px;
margin-left: 7px;
}
.room_content {
clear: left;
}
.notif {
border-bottom: 1px solid #e5e5e5;
margin-top: 16px;
padding-bottom: 16px;
}
.historical {
opacity: 0.3;
}
.message {
position: relative;
margin-bottom: 10px;
}
.sender_avatar {
width: 32px;
height: 32px;
border-radius: 16px;
position: absolute;
margin-left: 14px;
margin-top: -2px;
}
.sender_name {
margin-left: 75px;
display: inline;
font-size: 13px;
color: #a2a2a2;
}
.message_time {
float: right;
font-size: 11px;
color: #a2a2a2;
}
.message_body {
margin-left: 75px;
}
.notif_link {
margin-left: 75px;
font-weight: bold;
}
.notif_link a, .footer a {
color: #76CFA6;
text-decoration: none;
}
.footer {
margin-top: 20px;
text-align: center;
}

View File

@ -1,34 +0,0 @@
<div class="notif">
<div>
{% for message in notif.messages %}
<div class="message {% if message.is_historical %}historical{% endif %}">
{% if message.sender_avatar_url %}
<img alt="" class="sender_avatar" src="{{ message.sender_avatar_url|mxc_to_http(32,32) }}" />
{% else %}
{% if message.sender_hash % 3 == 0 %}
<img class="sender_avatar" src="https://vector.im/beta/img/76cfa6.png" />
{% elif message.sender_hash % 3 == 1 %}
<img class="sender_avatar" src="https://vector.im/beta/img/50e2c2.png" />
{% else %}
<img class="sender_avatar" src="https://vector.im/beta/img/f4c371.png" />
{% endif %}
<img class="sender_avatar" src="{{ message.sender_avatar_url }}" />
{% endif %}
<div class="sender_name">{{ message.sender_name }}</div>
<div class="message_time">{{ message.ts|format_ts("%H:%M") }}</div>
<div class="message_body">
{% if message.msgtype == "m.text" %}
{{ message.body_text_html }}
{% elif message.msgtype == "m.image" %}
<img src="{{ message.image_url|mxc_to_http(640, 480, scale) }}" />
{% elif message.msgtype == "m.file" %}
<span class="filename">{{ message.body_text_plain }}</span>
{% endif %}
</div>
</div>
{% endfor %}
</div>
<div class="notif_link">
<a href="{{ notif.link }}">View {{ room.title }}</a>
</div>
</div>

View File

@ -1,12 +0,0 @@
{% for message in notif.messages %}
{{ message.sender_name }} ({{ message.ts|format_ts("%H:%M") }})
{% if message.msgtype == "m.text" %}
{{ message.body_text_plain }}
{% elif message.msgtype == "m.image" %}
{{ message.body_text_plain }}
{% elif message.msgtype == "m.file" %}
{{ message.body_text_plain }}
{% endif %}
{% endfor %}
View at {{ notif.link }}

View File

@ -1,25 +0,0 @@
<!doctype html>
<html lang="en">
<head>
<style type="text/css">
{% include 'mail.css' without context %}
</style>
</head>
<body>
<div id="page">
<div class="header">
<img class="logo" src="http://matrix.org/img/vector-logo-email.png" width="64" height="83" alt="[Vector]"/>
<div class="salutation">Hi {{ user_display_name }},</div>
<div class="summarytext">{{ summary_text }}</div>
</div>
<div class="content">
{% for room in rooms %}
{% include 'room.html' with context %}
{% endfor %}
</div>
<div class="footer">
<a href="{{ unsubscribe_link }}">Unsubscribe</a>
</div>
</div>
</body>
</html>

View File

@ -1,10 +0,0 @@
Hi {{ user_display_name }},
{{ summary_text }}
{% for room in rooms %}
{% include 'room.txt' with context %}
{% endfor %}
You can disable these notifications at {{ unsubscribe_link }}

View File

@ -1,27 +0,0 @@
<div class="room">
<div class="room_header">
<div class="room_avatar">
{% if room.avatar_url %}
<img alt="" src="{{ room.avatar_url|mxc_to_http(48,48) }}" />
{% else %}
{% if room.hash % 3 == 0 %}
<img alt="" src="https://vector.im/beta/img/76cfa6.png" />
{% elif room.hash % 3 == 1 %}
<img alt="" src="https://vector.im/beta/img/50e2c2.png" />
{% else %}
<img alt="" src="https://vector.im/beta/img/f4c371.png" />
{% endif %}
{% endif %}
</div>
<h2>{{ room.title }}</h2>
</div>
<div class="room_content">
{% if room.invite %}
<a href="{{ room.link }}">Join the conversation.</a>
{% else %}
{% for notif in room.notifs %}
{% include 'notif.html' with context %}
{% endfor %}
{% endif %}
</div>
</div>

View File

@ -1,9 +0,0 @@
{{ room.title }}
{% if room.invite %}
You've been invited, join at {{ room.link }}
{% else %}
{% for notif in room.notifs %}
{% include 'notif.txt' with context %}
{% endfor %}
{% endif %}

View File

@ -1,21 +1,146 @@
body {
margin: 0px;
}
#page {
font-family: 'Open Sans', Helvetica, Arial, Sans-Serif;
font-color: #454545;
font-size: 12pt;
width: 100%;
padding: 20px;
}
#inner {
width: 640px;
}
.header {
width: 100%;
height: 87px;
color: #454545;
border-bottom: 4px solid #e5e5e5;
}
.logo {
text-align: right;
margin-left: 20px;
}
.salutation {
padding-top: 10px;
font-weight: bold;
}
.summarytext {
}
.room {
width: 100%;
color: #454545;
border-bottom: 1px solid #e5e5e5;
}
.room_header td {
padding-top: 38px;
padding-bottom: 10px;
border-bottom: 1px solid #e5e5e5;
}
.room_name {
vertical-align: middle;
font-size: 18px;
font-weight: bold;
}
.room_header h2 {
margin-top: 0px;
margin-left: 75px;
font-size: 20px;
}
.room_avatar { .room_avatar {
width: 56px;
line-height: 0px;
text-align: center;
vertical-align: middle;
}
.room_avatar img {
width: 48px; width: 48px;
height: 48px; height: 48px;
float: left; object-fit: cover;
border-radius: 24px;
} }
.room_content { .notif {
clear: left; border-bottom: 1px solid #e5e5e5;
margin-top: 16px;
padding-bottom: 16px;
} }
.historical { .historical_message .sender_avatar {
color: #888; opacity: 0.3;
}
/* spell out opacity and historical_message class names for Outlook aka Word */
.historical_message .sender_name {
color: #e3e3e3;
}
.historical_message .message_time {
color: #e3e3e3;
}
.historical_message .message_body {
color: #c7c7c7;
}
.historical_message td,
.message td {
padding-top: 10px;
}
.sender_avatar {
width: 56px;
text-align: center;
vertical-align: top;
}
.sender_avatar img {
margin-top: -2px;
width: 32px;
height: 32px;
border-radius: 16px;
} }
.sender_name { .sender_name {
display: inline; display: inline;
font-size: 13px;
color: #a2a2a2;
} }
.message_time { .message_time {
display: inline; text-align: right;
width: 100px;
font-size: 11px;
color: #a2a2a2;
}
.message_body {
}
.notif_link td {
padding-top: 10px;
padding-bottom: 10px;
font-weight: bold;
}
.notif_link a, .footer a {
color: #454545;
text-decoration: none;
}
.footer {
margin-top: 20px;
text-align: center;
} }

View File

@ -1,9 +1,9 @@
<div class="notif"> {% for message in notif.messages %}
<div> <tr class="{{ "historical_message" if message.is_historical else "message" }}">
{% for message in notif.messages %} <td class="sender_avatar">
<div class="message {% if message.is_historical %}historical{% endif %}"> {% if loop.index0 == 0 or notif.messages[loop.index0 - 1].sender_name != notif.messages[loop.index0].sender_name %}
{% if message.sender_avatar_url %} {% if message.sender_avatar_url %}
<img class="sender_avatar" src="{{ message.sender_avatar_url|mxc_to_http(48,48) }}" /> <img alt="" class="sender_avatar" src="{{ message.sender_avatar_url|mxc_to_http(32,32) }}" />
{% else %} {% else %}
{% if message.sender_hash % 3 == 0 %} {% if message.sender_hash % 3 == 0 %}
<img class="sender_avatar" src="https://vector.im/beta/img/76cfa6.png" /> <img class="sender_avatar" src="https://vector.im/beta/img/76cfa6.png" />
@ -14,21 +14,29 @@
{% endif %} {% endif %}
<img class="sender_avatar" src="{{ message.sender_avatar_url }}" /> <img class="sender_avatar" src="{{ message.sender_avatar_url }}" />
{% endif %} {% endif %}
{% endif %}
</td>
<td class="message_contents">
{% if loop.index0 == 0 or notif.messages[loop.index0 - 1].sender_name != notif.messages[loop.index0].sender_name %}
<div class="sender_name">{{ message.sender_name }}</div> <div class="sender_name">{{ message.sender_name }}</div>
<div class="message_time">{{ message.ts|format_ts("%H:%M") }}</div> {% endif %}
<div class="message_body"> <div class="message_body">
{% if message.msgtype == "m.text" %} {% if message.msgtype == "m.text" %}
{{ message.body_text_html }} {{ message.body_text_html }}
{% elif message.msgtype == "m.image" %} {% elif message.msgtype == "m.image" %}
<img src="{{ message.image_url|mxc_to_http(640, 480, scale) }}" /> <img src="{{ message.image_url|mxc_to_http(640, 480, scale) }}" />
{% elif message.msgtype == "m.file" %} {% elif message.msgtype == "m.file" %}
<span class="filename">{{ message.body_text_plain }}</span> <span class="filename">{{ message.body_text_plain }}</span>
{% endif %} {% endif %}
</div>
</div> </div>
{% endfor %} </td>
</div> <td class="message_time">{{ message.ts|format_ts("%H:%M") }}</td>
<div class="notif_link"> </tr>
<a href="{{ notif.link }}">View</a> {% endfor %}
</div> <tr class="notif_link">
</div> <td></td>
<td>
<a href="{{ notif.link }}">View {{ room.title }}</a>
</td>
<td></td>
</tr>

View File

@ -9,4 +9,4 @@
{% endif %} {% endif %}
{% endfor %} {% endfor %}
View at {{ notif.link }} View {{ room.title }} at {{ notif.link }}

View File

@ -3,20 +3,38 @@
<head> <head>
<style type="text/css"> <style type="text/css">
{% include 'mail.css' without context %} {% include 'mail.css' without context %}
{% include "mail-%s.css" % app_name ignore missing without context %}
</style> </style>
</head> </head>
<body> <body>
<div id="page"> <table id="page">
<div className="salutation">Hi {{ user_display_name }},</div> <tr>
<div className="summarytext">{{ summary_text }}</div> <td> </td>
<div class="content"> <td id="inner">
{% for room in rooms %} <table class="header">
{% include 'room.html' with context %} <tr>
{% endfor %} <td>
</div> <div class="salutation">Hi {{ user_display_name }},</div>
<div class="footer"> <div class="summarytext">{{ summary_text }}</div>
<a href="{{ unsubscribe_link }}">Unsubscribe</a> </td>
</div> <td class="logo">
</div> {% if app_name == "Vector" %}
<img src="http://matrix.org/img/vector-logo-email.png" width="64" height="83" alt="[Vector]"/>
{% else %}
<img src="http://matrix.org/img/matrix-94px-white.png" width="94" height="40" alt="[matrix]"/>
{% endif %}
</td>
</tr>
</table>
{% for room in rooms %}
{% include 'room.html' with context %}
{% endfor %}
<div class="footer">
<a href="{{ unsubscribe_link }}">Unsubscribe</a>
</div>
</td>
<td> </td>
</tr>
</table>
</body> </body>
</html> </html>

View File

@ -1,25 +1,33 @@
<div class="room"> <table class="room">
<div class="room_avatar"> <tr class="room_header">
{% if room.avatar_url %} <td class="room_avatar">
<img src="{{ room.avatar_url|mxc_to_http(48,48) }}" /> {% if room.avatar_url %}
{% else %} <img alt="" src="{{ room.avatar_url|mxc_to_http(48,48) }}" />
{% if room.hash % 3 == 0 %}
<img src="https://vector.im/beta/img/76cfa6.png" />
{% elif room.hash % 3 == 1 %}
<img src="https://vector.im/beta/img/50e2c2.png" />
{% else %} {% else %}
<img src="https://vector.im/beta/img/f4c371.png" /> {% if room.hash % 3 == 0 %}
<img alt="" src="https://vector.im/beta/img/76cfa6.png" />
{% elif room.hash % 3 == 1 %}
<img alt="" src="https://vector.im/beta/img/50e2c2.png" />
{% else %}
<img alt="" src="https://vector.im/beta/img/f4c371.png" />
{% endif %}
{% endif %} {% endif %}
{% endif %} </td>
</div> <td class="room_name" colspan="2">
<h2>{{ room.title }}</h2> {{ room.title }}
<div class="room_content"> </td>
{% if room.invite %} </tr>
<a href="{{ room.link }}">Join the conversation.</a> {% if room.invite %}
{% else %} <tr>
{% for notif in room.notifs %} <td></td>
{% include 'notif.html' with context %} <td>
{% endfor %} <a href="{{ room.link }}">Join the conversation.</a>
{% endif %} </td>
</div> <td></td>
</div> </tr>
{% else %}
{% for notif in room.notifs %}
{% include 'notif.html' with context %}
{% endfor %}
{% endif %}
</table>

View File

@ -146,6 +146,7 @@ class Mailer(object):
"user_display_name": user_display_name, "user_display_name": user_display_name,
"unsubscribe_link": self.make_unsubscribe_link(), "unsubscribe_link": self.make_unsubscribe_link(),
"summary_text": summary_text, "summary_text": summary_text,
"app_name": self.app_name,
"rooms": rooms, "rooms": rooms,
} }
@ -164,6 +165,9 @@ class Mailer(object):
multipart_msg.attach(text_part) multipart_msg.attach(text_part)
multipart_msg.attach(html_part) multipart_msg.attach(html_part)
logger.info("Sending email push notification to %s" % email_address)
#logger.debug(html_text)
yield sendmail( yield sendmail(
self.hs.config.email_smtp_host, self.hs.config.email_smtp_host,
raw_from, raw_to, multipart_msg.as_string(), raw_from, raw_to, multipart_msg.as_string(),
@ -367,19 +371,26 @@ class Mailer(object):
} }
def make_room_link(self, room_id): def make_room_link(self, room_id):
# XXX: matrix.to
# need /beta for Universal Links to work on iOS # need /beta for Universal Links to work on iOS
return "https://vector.im/beta/#/room/%s" % (room_id,) if self.app_name == "Vector":
return "https://vector.im/beta/#/room/%s" % (room_id,)
else:
return "https://matrix.to/#/room/%s" % (room_id,)
def make_notif_link(self, notif): def make_notif_link(self, notif):
# XXX: matrix.to
# need /beta for Universal Links to work on iOS # need /beta for Universal Links to work on iOS
return "https://vector.im/beta/#/room/%s/%s" % ( if self.app_name == "Vector":
notif['room_id'], notif['event_id'] return "https://vector.im/beta/#/room/%s/%s" % (
) notif['room_id'], notif['event_id']
)
else:
return "https://matrix.to/#/room/%s/%s" % (
notif['room_id'], notif['event_id']
)
def make_unsubscribe_link(self): def make_unsubscribe_link(self):
return "https://vector.im/#/settings" # XXX: matrix.to # XXX: matrix.to
return "https://vector.im/#/settings"
def mxc_to_http_filter(self, value, width, height, resize_method="crop"): def mxc_to_http_filter(self, value, width, height, resize_method="crop"):
if value[0:6] != "mxc://": if value[0:6] != "mxc://":