SciPost Code Repository

Skip to content
Snippets Groups Projects
Commit 7e4a0daf authored by George Katsikas's avatar George Katsikas :goat:
Browse files

add newsletter email layout with tables

parent 35689633
No related branches found
No related tags found
No related merge requests found
...@@ -4,15 +4,22 @@ __license__ = "AGPL v3" ...@@ -4,15 +4,22 @@ __license__ = "AGPL v3"
import json import json
import os import os
import re
from django.conf.urls import static
from django.core.mail import EmailMultiAlternatives
from django.db import models, transaction from django.db import models, transaction
from django.contrib.auth.models import User from django.contrib.auth.models import User
from django.conf import settings from django.conf import settings
from django.contrib.auth.models import Group from django.contrib.auth.models import Group
from django.template.loader import render_to_string
from django.urls import reverse from django.urls import reverse
from django.utils.html import strip_tags
from mailchimp3 import MailChimp from mailchimp3 import MailChimp
from common.utils.models import get_current_domain
from .constants import ( from .constants import (
MAIL_LIST_STATUSES, MAIL_LIST_STATUSES,
MAIL_LIST_STATUS_ACTIVE, MAIL_LIST_STATUS_ACTIVE,
...@@ -269,11 +276,48 @@ class Newsletter(models.Model): ...@@ -269,11 +276,48 @@ class Newsletter(models.Model):
else: else:
return f"{self.title} (no mailing list)" return f"{self.title} (no mailing list)"
@property
def email_content(self):
"""
Return full HTML content of the email including the header, footer and styling.
"""
# Load css content
css_path = os.path.join(
settings.BASE_DIR, "scipost/static/scipost/assets/css/newsletter.css"
)
css_content = re.sub(r"\s+", " ", open(css_path, "r").read())
domain = get_current_domain()
return render_to_string(
"mailing_lists/newsletter_email.html",
{
"newsletter": self,
"css_content": css_content,
"domain": domain,
},
)
def send(self): def send(self):
""" """
Creates the mailing task(s) to send the newsletter. Creates the mailing task(s) to send the newsletter.
""" """
pass # Remove the style tags from the email content and strip the tags
stripped_email_content = re.sub(r"<style>.+?</style>", "", self.email_content)
stripped_email_content = re.sub(
r"(\r?\n\r?){2,}", "\n\n", stripped_email_content, flags=re.MULTILINE
)
stripped_email_content = strip_tags(stripped_email_content).strip()
for subscriber in self.mailing_list.subscribed.all():
# Create a task to send the email to the subscriber
mail = EmailMultiAlternatives(
subject=f"[SciPost] {self.mailing_list.name}: {self.title}",
body=stripped_email_content,
from_email="SciPost <noreply@scipost.org>",
to=[subscriber.profile.email],
)
mail.attach_alternative(self.email_content, "text/html")
mail.send()
def get_media_folder(self): def get_media_folder(self):
""" """
......
{% load common_extras %}
<article>
<hgroup class="mb-2 d-flex justify-content-between align-items-center text-nowrap">
<h1 class="mb-0 text-truncate">{{ newsletter.title }}</h1>
<time datetime="{{ newsletter.updated_on|date:'c' }}">{{ newsletter.updated_on|date:'d M Y' }}</time>
</hgroup>
<section>
{{ newsletter.content|article_safe }}
</section>
</article>
{% load static %}
{% load common_extras %}
{% firstof newsletter.sent_on|date:"l j F Y" newsletter.created_on|date:"l j F Y" as newsletter_date %}
<div style="max-width:600px; margin: 0 auto" class="bg-white">
<!-- Header -->
<table class="bg-dark-blue w-100"
align="center"
border="0"
cellpadding="0"
cellspacing="0"
role="presentation">
<tbody>
<tr>
<td>
<a href="{% url 'scipost:index' %}">
<img src="{% static 'scipost/images/logo_scipost_RGB_HTML_groot.png' %}"
class="m-0 p-2 px-4"
alt="SciPost logo"
style="max-width: unset"
width="180"
height="55" />
</a>
</td>
<td class="fs-4 px-4">
<p class="text-right text-light-blue m-0">{{ newsletter.mailing_list.name }} Newsletter</p>
</td>
</tr>
</tbody>
</table>
<!-- Title -->
<table class="bg-dark-blue w-100"
align="center"
border="0"
cellpadding="0"
cellspacing="0"
role="presentation">
<tbody>
<tr>
<td class="pt-2 px-4">
<h1 class="text-light-blue m-0">{{ newsletter.title }}</h1>
</td>
</tr>
<tr>
<td class="pb-2 px-4">
<p class="text-light-blue m-0">{{ newsletter_date }}</p>
</td>
</tr>
</tbody>
</table>
<!-- Content -->
<table class="bg-white w-100"
align="center"
border="0"
cellpadding="0"
cellspacing="0"
role="presentation">
<tbody>
<tr>
<td>{{ newsletter.content|article_safe }}</td>
</tr>
</tbody>
</table>
<!-- Footer -->
<table class="bg-dark-blue w-100"
align="center"
border="0"
cellpadding="0"
cellspacing="0"
role="presentation">
<tbody>
<tr>
<td class="p-3">
<p class="text-center text-light-blue">
You are receiving this email because you are subscribed to the {{ newsletter.mailing_list.name }} mailing list.
Visit the "Email Preferences" tab on your <a class="text-light-blue" href="{% url "scipost:personal_page" %}">personal page</a> to manage your subscriptions.
</p>
</td>
</tr>
</tbody>
</table>
</div>
{% load static %}
{% firstof newsletter.sent_on newsletter.scheduled_for newsletter.created_on as newsletter_date %}
<html xmlns="http://www.w3.org/1999/xhtml"> <html xmlns="http://www.w3.org/1999/xhtml">
<head> <head>
<meta charset="UTF-8" /> <meta charset="UTF-8" />
...@@ -9,32 +6,5 @@ ...@@ -9,32 +6,5 @@
<base href="https://{{ domain }}/" target="_blank" /> <base href="https://{{ domain }}/" target="_blank" />
<style>{{css_content}}</style> <style>{{css_content}}</style>
</head> </head>
<body> <body class="bg-gray">{% include "mailing_lists/_newsletter_email_body.html" %}</body>
<header class="newsletter-header">
<a href="{% url 'scipost:index' %}">
<img src="{% static 'scipost/images/logo_scipost_RGB_HTML_groot.png' %}"
class="m-0 p-0"
alt="SciPost logo"
style="max-width: unset"
width="180"
height="55" />
</a>
<p class="text-light-blue m-0">{{ newsletter.mailing_list.name }} Newsletter</p>
</header>
<hgroup class="bg-dark-blue p-2 px-4">
<h1 class="text-light-blue m-0">{{ newsletter.title }}</h1>
<p class="text-light-blue m-0">{{ newsletter.created_on|date:"l j F Y" }}</p>
</hgroup>
{{ newsletter.content|safe }}
</body>
<footer class="bg-dark-blue p-3 mt-4">
<p class="text-center text-light-blue">
You are receiving this email because you are subscribed to the {{ newsletter.mailing_list.name }} mailing list.
Visit the "Email Preferences" tab on your <a class="text-light-blue" href="{% url "scipost:personal_page" %}">personal page</a> to manage your subscriptions.
</p>
</footer>
</html> </html>
...@@ -228,7 +228,7 @@ def _hx_newsletter_display(request, pk): ...@@ -228,7 +228,7 @@ def _hx_newsletter_display(request, pk):
return TemplateResponse( return TemplateResponse(
request, request,
"mailing_lists/_hx_newsletter_display.html", "mailing_lists/_newsletter_email_body.html",
{"newsletter": newsletter}, {"newsletter": newsletter},
) )
......
...@@ -2,6 +2,29 @@ ...@@ -2,6 +2,29 @@
/* This file holds a limited set of classes to be used in rendering the newsletter, particularly in email clients */ /* This file holds a limited set of classes to be used in rendering the newsletter, particularly in email clients */
body {
margin: 0;
padding: 0;
-webkit-text-size-adjust: 100%;
-ms-text-size-adjust: 100%;
}
table,
td {
border-collapse: collapse;
mso-table-lspace: 0pt;
mso-table-rspace: 0pt;
}
img {
border: 0;
height: auto;
line-height: 100%;
outline: none;
text-decoration: none;
-ms-interpolation-mode: bicubic;
}
h1 { h1 {
margin: 0; margin: 0;
} }
...@@ -30,12 +53,19 @@ p { ...@@ -30,12 +53,19 @@ p {
margin: 0; margin: 0;
padding: 0; padding: 0;
color: #002b49; color: #002b49;
text-align: justify;
} }
p+p { p+p {
margin-top: 1rem; margin-top: 1rem;
} }
table+table {
margin-top: 1rem;
}
.float-left { .float-left {
float: left; float: left;
} }
...@@ -83,6 +113,22 @@ p+p { ...@@ -83,6 +113,22 @@ p+p {
background-color: #002b49 !important; background-color: #002b49 !important;
} }
.bg-white {
background-color: #fff !important;
}
.bg-gray {
background-color: #f0f0f0;
}
.text-right{
text-align: right;
}
.text-left {
text-align: left;
}
.header { .header {
margin: 1rem 0 0.75rem 0; margin: 1rem 0 0.75rem 0;
font-size: 1.25rem; font-size: 1.25rem;
...@@ -91,12 +137,6 @@ p+p { ...@@ -91,12 +137,6 @@ p+p {
color: #fff; color: #fff;
} }
.item {
display: flex;
flex-direction: column;
margin-bottom: 1rem;
}
.item .content { .item .content {
padding: 0rem 2rem; padding: 0rem 2rem;
} }
...@@ -129,10 +169,22 @@ p+p { ...@@ -129,10 +169,22 @@ p+p {
padding: 2rem; padding: 2rem;
} }
.pt-2 {
padding-top: 0.5rem;
}
.pb-2 {
padding-bottom: 0.5rem;
}
.px-4 { .px-4 {
padding-left: 2rem; padding-left: 2rem;
padding-right: 2rem; padding-right: 2rem;
} }
.mx-4 {
margin-left: 2rem;
margin-right: 2rem;
}
.mb-2 { .mb-2 {
margin-bottom: 0.5rem; margin-bottom: 0.5rem;
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment