diff --git a/app/email_utils.py b/app/email_utils.py
index c6c8fcc4..3934d51b 100644
--- a/app/email_utils.py
+++ b/app/email_utils.py
@@ -20,7 +20,7 @@ from app.config import (
from app.log import LOG
-def _render(template_name, **kwargs) -> str:
+def render(template_name, **kwargs) -> str:
templates_dir = os.path.join(ROOT_DIR, "templates", "emails")
env = Environment(loader=FileSystemLoader(templates_dir))
@@ -33,8 +33,8 @@ def send_welcome_email(user):
send_email(
user.email,
f"Welcome to SimpleLogin {user.name}",
- _render("welcome.txt", name=user.name, user=user),
- _render("welcome.html", name=user.name, user=user),
+ render("com/welcome.txt", name=user.name, user=user),
+ render("com/welcome.html", name=user.name, user=user),
)
@@ -42,8 +42,8 @@ def send_trial_end_soon_email(user):
send_email(
user.email,
f"Your trial will end soon {user.name}",
- _render("trial-end.txt", name=user.name, user=user),
- _render("trial-end.html", name=user.name, user=user),
+ render("transactional/trial-end.txt", name=user.name, user=user),
+ render("transactional/trial-end.html", name=user.name, user=user),
)
@@ -51,11 +51,17 @@ def send_activation_email(email, name, activation_link):
send_email(
email,
f"Just one more step to join SimpleLogin {name}",
- _render(
- "activation.txt", name=name, activation_link=activation_link, email=email
+ render(
+ "transactional/activation.txt",
+ name=name,
+ activation_link=activation_link,
+ email=email,
),
- _render(
- "activation.html", name=name, activation_link=activation_link, email=email
+ render(
+ "transactional/activation.html",
+ name=name,
+ activation_link=activation_link,
+ email=email,
),
)
@@ -64,11 +70,15 @@ def send_reset_password_email(email, name, reset_password_link):
send_email(
email,
f"Reset your password on SimpleLogin",
- _render(
- "reset-password.txt", name=name, reset_password_link=reset_password_link
+ render(
+ "transactional/reset-password.txt",
+ name=name,
+ reset_password_link=reset_password_link,
),
- _render(
- "reset-password.html", name=name, reset_password_link=reset_password_link
+ render(
+ "transactional/reset-password.html",
+ name=name,
+ reset_password_link=reset_password_link,
),
)
@@ -77,15 +87,15 @@ def send_change_email(new_email, current_email, name, link):
send_email(
new_email,
f"Confirm email update on SimpleLogin",
- _render(
- "change-email.txt",
+ render(
+ "transactional/change-email.txt",
name=name,
link=link,
new_email=new_email,
current_email=current_email,
),
- _render(
- "change-email.html",
+ render(
+ "transactional/change-email.html",
name=name,
link=link,
new_email=new_email,
@@ -98,8 +108,8 @@ def send_new_app_email(email, name):
send_email(
email,
f"Any question/feedback for SimpleLogin {name}?",
- _render("new-app.txt", name=name),
- _render("new-app.html", name=name),
+ render("com/new-app.txt", name=name),
+ render("com/new-app.html", name=name),
)
@@ -107,8 +117,8 @@ def send_test_email_alias(email, name):
send_email(
email,
f"This email is sent to {email}",
- _render("test-email.txt", name=name, alias=email),
- _render("test-email.html", name=name, alias=email),
+ render("transactional/test-email.txt", name=name, alias=email),
+ render("transactional/test-email.html", name=name, alias=email),
)
@@ -119,14 +129,14 @@ def send_cannot_create_directory_alias(user, alias, directory):
send_email(
user.email,
f"Alias {alias} cannot be created",
- _render(
- "cannot-create-alias-directory.txt",
+ render(
+ "transactional/cannot-create-alias-directory.txt",
name=user.name,
alias=alias,
directory=directory,
),
- _render(
- "cannot-create-alias-directory.html",
+ render(
+ "transactional/cannot-create-alias-directory.html",
name=user.name,
alias=alias,
directory=directory,
@@ -141,11 +151,14 @@ def send_cannot_create_domain_alias(user, alias, domain):
send_email(
user.email,
f"Alias {alias} cannot be created",
- _render(
- "cannot-create-alias-domain.txt", name=user.name, alias=alias, domain=domain
+ render(
+ "transactional/cannot-create-alias-domain.txt",
+ name=user.name,
+ alias=alias,
+ domain=domain,
),
- _render(
- "cannot-create-alias-domain.html",
+ render(
+ "transactional/cannot-create-alias-domain.html",
name=user.name,
alias=alias,
domain=domain,
@@ -161,15 +174,15 @@ def send_reply_alias_must_use_personal_email(user, alias, sender):
send_email(
user.email,
f"Reply from your alias {alias} only works with your personal email",
- _render(
- "reply-must-use-personal-email.txt",
+ render(
+ "transactional/reply-must-use-personal-email.txt",
name=user.name,
alias=alias,
sender=sender,
user_email=user.email,
),
- _render(
- "reply-must-use-personal-email.html",
+ render(
+ "transactional/reply-must-use-personal-email.html",
name=user.name,
alias=alias,
sender=sender,
diff --git a/cron.py b/cron.py
index cc2fae0e..dd61bbad 100644
--- a/cron.py
+++ b/cron.py
@@ -1,3 +1,5 @@
+import argparse
+
import arrow
from app.config import IGNORED_EMAILS, ADMIN_EMAIL
@@ -16,7 +18,7 @@ from app.models import (
from server import create_app
-def send_trial_end_soon():
+def notify_trial_end():
for user in User.query.filter(User.trial_end.isnot(None)).all():
if arrow.now().shift(days=3) > user.trial_end >= arrow.now().shift(days=2):
LOG.d("Send trial end email to user %s", user)
@@ -106,8 +108,22 @@ nb_app: {nb_app}
if __name__ == "__main__":
LOG.d("Start running cronjob")
+ parser = argparse.ArgumentParser()
+ parser.add_argument(
+ "-j",
+ "--job",
+ help="Choose a cron job to run",
+ type=str,
+ choices=["stats", "notify_trial_end",],
+ )
+ args = parser.parse_args()
+
app = create_app()
with app.app_context():
- stats()
- send_trial_end_soon()
+ if args.job == "stats":
+ LOG.d("Compute Stats")
+ stats()
+ elif args.job == "notify_trial_end":
+ LOG.d("Notify users with trial ending soon")
+ notify_trial_end()
diff --git a/crontab.yml b/crontab.yml
index 579277c2..373138ae 100644
--- a/crontab.yml
+++ b/crontab.yml
@@ -1,6 +1,12 @@
jobs:
- - name: SimpleLogin cronjob
- command: python /code/cron.py
+ - name: SimpleLogin stats
+ command: python /code/cron.py -j stats
shell: /bin/bash
schedule: "0 0 * * *"
captureStderr: true
+
+ - name: SimpleLogin Notify Trial Ends
+ command: python /code/cron.py -j notify_trial_end
+ shell: /bin/bash
+ schedule: "0 8 * * *"
+ captureStderr: true
diff --git a/shell.py b/shell.py
index 49d28955..004dd802 100644
--- a/shell.py
+++ b/shell.py
@@ -3,10 +3,9 @@ from IPython import embed
from sqlalchemy_utils import create_database, database_exists, drop_database
from app.config import DB_URI
-from app.email_utils import _render
+from app.email_utils import send_email, render
from app.models import *
from server import create_app
-from app import email_utils
def create_db():
@@ -31,6 +30,16 @@ def reset_db():
create_db()
+def send_safari_extension_newsletter():
+ for user in User.query.all():
+ send_email(
+ user.email,
+ "Quickly create alias with our Safari extension",
+ render("com/safari-extension.txt", user=user),
+ render("com/safari-extension.html", user=user),
+ )
+
+
app = create_app()
with app.app_context():
diff --git a/templates/emails/new-app.html b/templates/emails/com/new-app.html
similarity index 100%
rename from templates/emails/new-app.html
rename to templates/emails/com/new-app.html
diff --git a/templates/emails/new-app.txt b/templates/emails/com/new-app.txt
similarity index 100%
rename from templates/emails/new-app.txt
rename to templates/emails/com/new-app.txt
diff --git a/templates/emails/com/safari-extension.html b/templates/emails/com/safari-extension.html
new file mode 100644
index 00000000..bbb757e5
--- /dev/null
+++ b/templates/emails/com/safari-extension.html
@@ -0,0 +1,19 @@
+{% extends "base.html" %}
+
+{% block content %}
+ {{ render_text("This email is sent to " + user.email + ".") }}
+
+ {{ render_text('Unsubscribe from our emails on https://app.simplelogin.io/dashboard/setting#notification') }}
+
+ {{ render_text("