mirror of
https://github.com/minetest/contentdb.git
synced 2024-12-23 06:22:24 +01:00
Use persistent SMTP connection for bulk emails, add List-Unsubscribe header
This commit is contained in:
parent
8ad066409c
commit
770d17b42a
@ -21,7 +21,7 @@ from wtforms import TextAreaField, SubmitField, StringField
|
|||||||
from wtforms.validators import InputRequired, Length
|
from wtforms.validators import InputRequired, Length
|
||||||
|
|
||||||
from app.markdown import render_markdown
|
from app.markdown import render_markdown
|
||||||
from app.tasks.emails import send_user_email
|
from app.tasks.emails import send_user_email, send_bulk_email as task_send_bulk
|
||||||
from app.utils import rank_required, addAuditLog
|
from app.utils import rank_required, addAuditLog
|
||||||
from . import bp
|
from . import bp
|
||||||
from ...models import UserRank, User, AuditSeverity
|
from ...models import UserRank, User, AuditSeverity
|
||||||
@ -70,8 +70,7 @@ def send_bulk_email():
|
|||||||
|
|
||||||
text = form.text.data
|
text = form.text.data
|
||||||
html = render_markdown(text)
|
html = render_markdown(text)
|
||||||
for user in User.query.filter(User.email.isnot(None)).all():
|
task_send_bulk.delay(form.subject.data, text, html)
|
||||||
send_user_email.delay(user.email, user.locale or "en", form.subject.data, text, html)
|
|
||||||
|
|
||||||
return redirect(url_for("admin.admin_page"))
|
return redirect(url_for("admin.admin_page"))
|
||||||
|
|
||||||
|
@ -309,6 +309,11 @@ class EmailSubscription(db.Model):
|
|||||||
self.blacklisted = False
|
self.blacklisted = False
|
||||||
self.token = None
|
self.token = None
|
||||||
|
|
||||||
|
@property
|
||||||
|
def url(self):
|
||||||
|
from ..utils import abs_url_for
|
||||||
|
return abs_url_for('users.unsubscribe', token=self.token)
|
||||||
|
|
||||||
|
|
||||||
class NotificationType(enum.Enum):
|
class NotificationType(enum.Enum):
|
||||||
# Package / release / etc
|
# Package / release / etc
|
||||||
|
@ -14,9 +14,10 @@
|
|||||||
# You should have received a copy of the GNU Affero General Public License
|
# You should have received a copy of the GNU Affero General Public License
|
||||||
# along with this program. If not, see <https://www.gnu.org/licenses/>.
|
# along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
|
from typing import Dict
|
||||||
|
|
||||||
from flask import render_template, escape
|
from flask import render_template, escape
|
||||||
from flask_babel import force_locale, gettext
|
from flask_babel import force_locale, gettext, lazy_gettext
|
||||||
from flask_mail import Message
|
from flask_mail import Message
|
||||||
from app import mail
|
from app import mail
|
||||||
from app.models import Notification, db, EmailSubscription, User
|
from app.models import Notification, db, EmailSubscription, User
|
||||||
@ -36,6 +37,10 @@ def get_email_subscription(email):
|
|||||||
return ret
|
return ret
|
||||||
|
|
||||||
|
|
||||||
|
def gen_headers(sub: EmailSubscription) -> Dict[str,str]:
|
||||||
|
return {"List-Help": f"<{abs_url_for('flatpage', path='help/faq/')}>", "List-Unsubscribe": f"<{sub.url}>"}
|
||||||
|
|
||||||
|
|
||||||
@celery.task()
|
@celery.task()
|
||||||
def send_verify_email(email, token, locale):
|
def send_verify_email(email, token, locale):
|
||||||
sub = get_email_subscription(email)
|
sub = get_email_subscription(email)
|
||||||
@ -43,7 +48,7 @@ def send_verify_email(email, token, locale):
|
|||||||
return
|
return
|
||||||
|
|
||||||
with force_locale(locale or "en"):
|
with force_locale(locale or "en"):
|
||||||
msg = Message("Confirm email address", recipients=[email])
|
msg = Message("Confirm email address", recipients=[email], extra_headers=gen_headers(sub))
|
||||||
|
|
||||||
msg.body = """
|
msg.body = """
|
||||||
This email has been sent to you because someone (hopefully you)
|
This email has been sent to you because someone (hopefully you)
|
||||||
@ -67,7 +72,7 @@ def send_unsubscribe_verify(email, locale):
|
|||||||
return
|
return
|
||||||
|
|
||||||
with force_locale(locale or "en"):
|
with force_locale(locale or "en"):
|
||||||
msg = Message("Confirm unsubscribe", recipients=[email])
|
msg = Message("Confirm unsubscribe", recipients=[email], extra_headers=gen_headers(sub))
|
||||||
|
|
||||||
msg.body = """
|
msg.body = """
|
||||||
We're sorry to see you go. You just need to do one more thing before your email is blacklisted.
|
We're sorry to see you go. You just need to do one more thing before your email is blacklisted.
|
||||||
@ -80,33 +85,33 @@ def send_unsubscribe_verify(email, locale):
|
|||||||
|
|
||||||
|
|
||||||
@celery.task(rate_limit="25/m")
|
@celery.task(rate_limit="25/m")
|
||||||
def send_email_with_reason(email: str, locale: str, subject: str, text: str, html: str, reason: str):
|
def send_email_with_reason(email: str, locale: str, subject: str, text: str, html: str, reason: str, conn: any):
|
||||||
sub = get_email_subscription(email)
|
sub = get_email_subscription(email)
|
||||||
if sub.blacklisted:
|
if sub.blacklisted:
|
||||||
return
|
return
|
||||||
|
|
||||||
with force_locale(locale or "en"):
|
with force_locale(locale or "en"):
|
||||||
from flask_mail import Message
|
msg = Message(subject, recipients=[email], extra_headers=gen_headers(sub))
|
||||||
msg = Message(subject, recipients=[email])
|
|
||||||
|
|
||||||
msg.body = text
|
msg.body = text
|
||||||
html = html or f"<pre>{escape(text)}</pre>"
|
html = html or f"<pre>{escape(text)}</pre>"
|
||||||
msg.html = render_template("emails/base.html", subject=subject, content=html, reason=reason, sub=sub)
|
msg.html = render_template("emails/base.html", subject=subject, content=html, reason=reason, sub=sub)
|
||||||
|
if conn:
|
||||||
|
conn.send(msg)
|
||||||
|
else:
|
||||||
mail.send(msg)
|
mail.send(msg)
|
||||||
|
|
||||||
|
|
||||||
@celery.task(rate_limit="25/m")
|
@celery.task(rate_limit="25/m")
|
||||||
def send_user_email(email: str, locale: str, subject: str, text: str, html=None):
|
def send_user_email(email: str, locale: str, subject: str, text: str, html=None, conn=None):
|
||||||
with force_locale(locale or "en"):
|
|
||||||
return send_email_with_reason(email, locale, subject, text, html,
|
return send_email_with_reason(email, locale, subject, text, html,
|
||||||
gettext("You are receiving this email because you are a registered user of ContentDB."))
|
lazy_gettext("You are receiving this email because you are a registered user of ContentDB."), conn)
|
||||||
|
|
||||||
|
|
||||||
@celery.task(rate_limit="25/m")
|
@celery.task(rate_limit="25/m")
|
||||||
def send_anon_email(email: str, locale: str, subject: str, text: str, html=None):
|
def send_anon_email(email: str, locale: str, subject: str, text: str, html=None):
|
||||||
with force_locale(locale or "en"):
|
|
||||||
return send_email_with_reason(email, locale, subject, text, html,
|
return send_email_with_reason(email, locale, subject, text, html,
|
||||||
gettext("You are receiving this email because someone (hopefully you) entered your email address as a user's email."))
|
lazy_gettext("You are receiving this email because someone (hopefully you) entered your email address as a user's email."))
|
||||||
|
|
||||||
|
|
||||||
def send_single_email(notification, locale):
|
def send_single_email(notification, locale):
|
||||||
@ -115,7 +120,7 @@ def send_single_email(notification, locale):
|
|||||||
return
|
return
|
||||||
|
|
||||||
with force_locale(locale or "en"):
|
with force_locale(locale or "en"):
|
||||||
msg = Message(notification.title, recipients=[notification.user.email])
|
msg = Message(notification.title, recipients=[notification.user.email], extra_headers=gen_headers(sub))
|
||||||
|
|
||||||
msg.body = """
|
msg.body = """
|
||||||
New notification: {}
|
New notification: {}
|
||||||
@ -187,3 +192,10 @@ def send_pending_notifications():
|
|||||||
send_notification_digest(to_send, user.locale or "en")
|
send_notification_digest(to_send, user.locale or "en")
|
||||||
elif len(to_send) > 0:
|
elif len(to_send) > 0:
|
||||||
send_single_email(to_send[0], user.locale or "en")
|
send_single_email(to_send[0], user.locale or "en")
|
||||||
|
|
||||||
|
|
||||||
|
@celery.task()
|
||||||
|
def send_bulk_email(subject: str, text: str, html=None):
|
||||||
|
with mail.connect() as conn:
|
||||||
|
for user in User.query.filter(User.email.isnot(None)).all():
|
||||||
|
send_user_email(user.email, user.locale or "en", subject, text, html, conn)
|
||||||
|
@ -59,7 +59,7 @@
|
|||||||
<p>
|
<p>
|
||||||
{% block footer %}
|
{% block footer %}
|
||||||
{{ reason }} <br>
|
{{ reason }} <br>
|
||||||
<a href="{{ abs_url_for('users.unsubscribe', token=sub.token) }}">
|
<a href="{{ sub.url }}">
|
||||||
{{ _("Unsubscribe") }}
|
{{ _("Unsubscribe") }}
|
||||||
</a>
|
</a>
|
||||||
{% endblock %}
|
{% endblock %}
|
||||||
|
Loading…
Reference in New Issue
Block a user