mirror of
https://github.com/simple-login/app.git
synced 2024-10-01 14:11:31 +02:00
rename ForwardEmail to Contact
This commit is contained in:
parent
3e73d16215
commit
f8f1e2124a
@ -13,7 +13,7 @@ from app.dashboard.views.index import get_alias_info, AliasInfo
|
|||||||
from app.extensions import db
|
from app.extensions import db
|
||||||
from app.log import LOG
|
from app.log import LOG
|
||||||
from app.models import ForwardEmailLog
|
from app.models import ForwardEmailLog
|
||||||
from app.models import GenEmail, ForwardEmail
|
from app.models import GenEmail, Contact
|
||||||
from app.utils import random_string
|
from app.utils import random_string
|
||||||
|
|
||||||
|
|
||||||
@ -199,7 +199,7 @@ def update_alias(alias_id):
|
|||||||
return jsonify(note=new_note), 200
|
return jsonify(note=new_note), 200
|
||||||
|
|
||||||
|
|
||||||
def serialize_forward_email(fe: ForwardEmail) -> dict:
|
def serialize_contact(fe: Contact) -> dict:
|
||||||
|
|
||||||
res = {
|
res = {
|
||||||
"creation_date": fe.created_at.format(),
|
"creation_date": fe.created_at.format(),
|
||||||
@ -220,15 +220,15 @@ def serialize_forward_email(fe: ForwardEmail) -> dict:
|
|||||||
|
|
||||||
def get_alias_contacts(gen_email, page_id: int) -> [dict]:
|
def get_alias_contacts(gen_email, page_id: int) -> [dict]:
|
||||||
q = (
|
q = (
|
||||||
ForwardEmail.query.filter_by(gen_email_id=gen_email.id)
|
Contact.query.filter_by(gen_email_id=gen_email.id)
|
||||||
.order_by(ForwardEmail.id.desc())
|
.order_by(Contact.id.desc())
|
||||||
.limit(PAGE_LIMIT)
|
.limit(PAGE_LIMIT)
|
||||||
.offset(page_id * PAGE_LIMIT)
|
.offset(page_id * PAGE_LIMIT)
|
||||||
)
|
)
|
||||||
|
|
||||||
res = []
|
res = []
|
||||||
for fe in q.all():
|
for fe in q.all():
|
||||||
res.append(serialize_forward_email(fe))
|
res.append(serialize_contact(fe))
|
||||||
|
|
||||||
return res
|
return res
|
||||||
|
|
||||||
@ -299,16 +299,16 @@ def create_contact_route(alias_id):
|
|||||||
reply_email = f"ra+{random_string(25)}@{EMAIL_DOMAIN}"
|
reply_email = f"ra+{random_string(25)}@{EMAIL_DOMAIN}"
|
||||||
for _ in range(1000):
|
for _ in range(1000):
|
||||||
reply_email = f"ra+{random_string(25)}@{EMAIL_DOMAIN}"
|
reply_email = f"ra+{random_string(25)}@{EMAIL_DOMAIN}"
|
||||||
if not ForwardEmail.get_by(reply_email=reply_email):
|
if not Contact.get_by(reply_email=reply_email):
|
||||||
break
|
break
|
||||||
|
|
||||||
_, website_email = parseaddr(contact_email)
|
_, website_email = parseaddr(contact_email)
|
||||||
|
|
||||||
# already been added
|
# already been added
|
||||||
if ForwardEmail.get_by(gen_email_id=gen_email.id, website_email=website_email):
|
if Contact.get_by(gen_email_id=gen_email.id, website_email=website_email):
|
||||||
return jsonify(error="Contact already added"), 409
|
return jsonify(error="Contact already added"), 409
|
||||||
|
|
||||||
forward_email = ForwardEmail.create(
|
contact = Contact.create(
|
||||||
gen_email_id=gen_email.id,
|
gen_email_id=gen_email.id,
|
||||||
website_email=website_email,
|
website_email=website_email,
|
||||||
website_from=contact_email,
|
website_from=contact_email,
|
||||||
@ -318,4 +318,4 @@ def create_contact_route(alias_id):
|
|||||||
LOG.d("create reverse-alias for %s %s", contact_email, gen_email)
|
LOG.d("create reverse-alias for %s %s", contact_email, gen_email)
|
||||||
db.session.commit()
|
db.session.commit()
|
||||||
|
|
||||||
return jsonify(**serialize_forward_email(forward_email)), 201
|
return jsonify(**serialize_contact(contact)), 201
|
||||||
|
@ -47,33 +47,33 @@
|
|||||||
</form>
|
</form>
|
||||||
|
|
||||||
<div class="row">
|
<div class="row">
|
||||||
{% for forward_email in forward_emails %}
|
{% for contact in contacts %}
|
||||||
<div class="col-md-6">
|
<div class="col-md-6">
|
||||||
<div class="my-2 p-2 card {% if forward_email.id == forward_email_id %} highlight-row {% endif %}">
|
<div class="my-2 p-2 card {% if contact.id == contact_id %} highlight-row {% endif %}">
|
||||||
<div>
|
<div>
|
||||||
<span>
|
<span>
|
||||||
<a href="{{ 'mailto:' + forward_email.website_send_to() }}"
|
<a href="{{ 'mailto:' + contact.website_send_to() }}"
|
||||||
data-toggle="tooltip"
|
data-toggle="tooltip"
|
||||||
title="You can click on this to open your email client. Or use the copy button 👉"
|
title="You can click on this to open your email client. Or use the copy button 👉"
|
||||||
class="font-weight-bold">*************************</a>
|
class="font-weight-bold">*************************</a>
|
||||||
|
|
||||||
<span class="clipboard btn btn-sm btn-success copy-btn" data-toggle="tooltip"
|
<span class="clipboard btn btn-sm btn-success copy-btn" data-toggle="tooltip"
|
||||||
title="Copy to clipboard"
|
title="Copy to clipboard"
|
||||||
data-clipboard-text="{{ forward_email.website_send_to() }}">
|
data-clipboard-text="{{ contact.website_send_to() }}">
|
||||||
Copy reverse-alias
|
Copy reverse-alias
|
||||||
</span>
|
</span>
|
||||||
</span>
|
</span>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div>
|
<div>
|
||||||
<i class="fe fe-mail"></i> ➡ {{ forward_email.website_from or forward_email.website_email }}
|
<i class="fe fe-mail"></i> ➡ {{ contact.website_from or contact.website_email }}
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="mb-2 text-muted small-text">
|
<div class="mb-2 text-muted small-text">
|
||||||
Created {{ forward_email.created_at | dt }} <br>
|
Created {{ contact.created_at | dt }} <br>
|
||||||
|
|
||||||
{% if forward_email.last_reply() %}
|
{% if contact.last_reply() %}
|
||||||
{% set email_log = forward_email.last_reply() %}
|
{% set email_log = contact.last_reply() %}
|
||||||
Last email sent {{ email_log.created_at | dt }}
|
Last email sent {{ email_log.created_at | dt }}
|
||||||
{% endif %}
|
{% endif %}
|
||||||
</div>
|
</div>
|
||||||
@ -81,7 +81,7 @@
|
|||||||
<div>
|
<div>
|
||||||
<form method="post">
|
<form method="post">
|
||||||
<input type="hidden" name="form-name" value="delete">
|
<input type="hidden" name="form-name" value="delete">
|
||||||
<input type="hidden" name="forward-email-id" value="{{ forward_email.id }}">
|
<input type="hidden" name="contact-id" value="{{ contact.id }}">
|
||||||
<span class="card-link btn btn-link float-right delete-forward-email">
|
<span class="card-link btn btn-link float-right delete-forward-email">
|
||||||
Delete
|
Delete
|
||||||
</span>
|
</span>
|
||||||
|
@ -10,7 +10,7 @@ from app.config import EMAIL_DOMAIN
|
|||||||
from app.dashboard.base import dashboard_bp
|
from app.dashboard.base import dashboard_bp
|
||||||
from app.extensions import db
|
from app.extensions import db
|
||||||
from app.log import LOG
|
from app.log import LOG
|
||||||
from app.models import GenEmail, ForwardEmail
|
from app.models import GenEmail, Contact
|
||||||
from app.utils import random_string
|
from app.utils import random_string
|
||||||
|
|
||||||
|
|
||||||
@ -47,10 +47,10 @@ class NewContactForm(FlaskForm):
|
|||||||
|
|
||||||
@dashboard_bp.route("/alias_contact_manager/<alias_id>/", methods=["GET", "POST"])
|
@dashboard_bp.route("/alias_contact_manager/<alias_id>/", methods=["GET", "POST"])
|
||||||
@dashboard_bp.route(
|
@dashboard_bp.route(
|
||||||
"/alias_contact_manager/<alias_id>/<int:forward_email_id>", methods=["GET", "POST"]
|
"/alias_contact_manager/<alias_id>/<contact_id>", methods=["GET", "POST"]
|
||||||
)
|
)
|
||||||
@login_required
|
@login_required
|
||||||
def alias_contact_manager(alias_id, forward_email_id=None):
|
def alias_contact_manager(alias_id, contact_id=None):
|
||||||
gen_email = GenEmail.get(alias_id)
|
gen_email = GenEmail.get(alias_id)
|
||||||
|
|
||||||
# sanity check
|
# sanity check
|
||||||
@ -71,15 +71,16 @@ def alias_contact_manager(alias_id, forward_email_id=None):
|
|||||||
|
|
||||||
# generate a reply_email, make sure it is unique
|
# generate a reply_email, make sure it is unique
|
||||||
# not use while to avoid infinite loop
|
# not use while to avoid infinite loop
|
||||||
|
reply_email = f"ra+{random_string(25)}@{EMAIL_DOMAIN}"
|
||||||
for _ in range(1000):
|
for _ in range(1000):
|
||||||
reply_email = f"ra+{random_string(25)}@{EMAIL_DOMAIN}"
|
reply_email = f"ra+{random_string(25)}@{EMAIL_DOMAIN}"
|
||||||
if not ForwardEmail.get_by(reply_email=reply_email):
|
if not Contact.get_by(reply_email=reply_email):
|
||||||
break
|
break
|
||||||
|
|
||||||
_, website_email = parseaddr(contact_email)
|
_, website_email = parseaddr(contact_email)
|
||||||
|
|
||||||
# already been added
|
# already been added
|
||||||
if ForwardEmail.get_by(
|
if Contact.get_by(
|
||||||
gen_email_id=gen_email.id, website_email=website_email
|
gen_email_id=gen_email.id, website_email=website_email
|
||||||
):
|
):
|
||||||
flash(f"{website_email} is already added", "error")
|
flash(f"{website_email} is already added", "error")
|
||||||
@ -87,7 +88,7 @@ def alias_contact_manager(alias_id, forward_email_id=None):
|
|||||||
url_for("dashboard.alias_contact_manager", alias_id=alias_id)
|
url_for("dashboard.alias_contact_manager", alias_id=alias_id)
|
||||||
)
|
)
|
||||||
|
|
||||||
forward_email = ForwardEmail.create(
|
contact = Contact.create(
|
||||||
gen_email_id=gen_email.id,
|
gen_email_id=gen_email.id,
|
||||||
website_email=website_email,
|
website_email=website_email,
|
||||||
website_from=contact_email,
|
website_from=contact_email,
|
||||||
@ -102,26 +103,26 @@ def alias_contact_manager(alias_id, forward_email_id=None):
|
|||||||
url_for(
|
url_for(
|
||||||
"dashboard.alias_contact_manager",
|
"dashboard.alias_contact_manager",
|
||||||
alias_id=alias_id,
|
alias_id=alias_id,
|
||||||
forward_email_id=forward_email.id,
|
contact_id=contact.id,
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
elif request.form.get("form-name") == "delete":
|
elif request.form.get("form-name") == "delete":
|
||||||
forward_email_id = request.form.get("forward-email-id")
|
contact_id = request.form.get("contact-id")
|
||||||
forward_email = ForwardEmail.get(forward_email_id)
|
contact = Contact.get(contact_id)
|
||||||
|
|
||||||
if not forward_email:
|
if not contact:
|
||||||
flash("Unknown error. Refresh the page", "warning")
|
flash("Unknown error. Refresh the page", "warning")
|
||||||
return redirect(
|
return redirect(
|
||||||
url_for("dashboard.alias_contact_manager", alias_id=alias_id)
|
url_for("dashboard.alias_contact_manager", alias_id=alias_id)
|
||||||
)
|
)
|
||||||
elif forward_email.gen_email_id != gen_email.id:
|
elif contact.gen_email_id != gen_email.id:
|
||||||
flash("You cannot delete reverse-alias", "warning")
|
flash("You cannot delete reverse-alias", "warning")
|
||||||
return redirect(
|
return redirect(
|
||||||
url_for("dashboard.alias_contact_manager", alias_id=alias_id)
|
url_for("dashboard.alias_contact_manager", alias_id=alias_id)
|
||||||
)
|
)
|
||||||
|
|
||||||
contact_name = forward_email.website_from
|
contact_name = contact.website_from
|
||||||
ForwardEmail.delete(forward_email_id)
|
Contact.delete(contact_id)
|
||||||
db.session.commit()
|
db.session.commit()
|
||||||
|
|
||||||
flash(f"Reverse-alias for {contact_name} has been deleted", "success")
|
flash(f"Reverse-alias for {contact_name} has been deleted", "success")
|
||||||
@ -130,19 +131,17 @@ def alias_contact_manager(alias_id, forward_email_id=None):
|
|||||||
url_for("dashboard.alias_contact_manager", alias_id=alias_id)
|
url_for("dashboard.alias_contact_manager", alias_id=alias_id)
|
||||||
)
|
)
|
||||||
|
|
||||||
# make sure highlighted forward_email is at array start
|
# make sure highlighted contact is at array start
|
||||||
forward_emails = gen_email.forward_emails
|
contacts = gen_email.contacts
|
||||||
|
|
||||||
if forward_email_id:
|
if contact_id:
|
||||||
forward_emails = sorted(
|
contacts = sorted(contacts, key=lambda fe: fe.id == contact_id, reverse=True)
|
||||||
forward_emails, key=lambda fe: fe.id == forward_email_id, reverse=True
|
|
||||||
)
|
|
||||||
|
|
||||||
return render_template(
|
return render_template(
|
||||||
"dashboard/alias_contact_manager.html",
|
"dashboard/alias_contact_manager.html",
|
||||||
forward_emails=forward_emails,
|
contacts=contacts,
|
||||||
alias=gen_email.email,
|
alias=gen_email.email,
|
||||||
gen_email=gen_email,
|
gen_email=gen_email,
|
||||||
new_contact_form=new_contact_form,
|
new_contact_form=new_contact_form,
|
||||||
forward_email_id=forward_email_id,
|
contact_id=contact_id,
|
||||||
)
|
)
|
||||||
|
@ -5,7 +5,7 @@ from flask_login import login_required, current_user
|
|||||||
from app.config import PAGE_LIMIT
|
from app.config import PAGE_LIMIT
|
||||||
from app.dashboard.base import dashboard_bp
|
from app.dashboard.base import dashboard_bp
|
||||||
from app.extensions import db
|
from app.extensions import db
|
||||||
from app.models import GenEmail, ForwardEmailLog, ForwardEmail
|
from app.models import GenEmail, ForwardEmailLog, Contact
|
||||||
|
|
||||||
|
|
||||||
class AliasLog:
|
class AliasLog:
|
||||||
@ -42,9 +42,9 @@ def alias_log(alias_id, page_id):
|
|||||||
|
|
||||||
logs = get_alias_log(gen_email, page_id)
|
logs = get_alias_log(gen_email, page_id)
|
||||||
base = (
|
base = (
|
||||||
db.session.query(ForwardEmail, ForwardEmailLog)
|
db.session.query(Contact, ForwardEmailLog)
|
||||||
.filter(ForwardEmail.id == ForwardEmailLog.forward_id)
|
.filter(Contact.id == ForwardEmailLog.forward_id)
|
||||||
.filter(ForwardEmail.gen_email_id == gen_email.id)
|
.filter(Contact.gen_email_id == gen_email.id)
|
||||||
)
|
)
|
||||||
total = base.count()
|
total = base.count()
|
||||||
email_forwarded = (
|
email_forwarded = (
|
||||||
@ -66,9 +66,9 @@ def get_alias_log(gen_email: GenEmail, page_id=0):
|
|||||||
mailbox = gen_email.mailbox_email()
|
mailbox = gen_email.mailbox_email()
|
||||||
|
|
||||||
q = (
|
q = (
|
||||||
db.session.query(ForwardEmail, ForwardEmailLog)
|
db.session.query(Contact, ForwardEmailLog)
|
||||||
.filter(ForwardEmail.id == ForwardEmailLog.forward_id)
|
.filter(Contact.id == ForwardEmailLog.forward_id)
|
||||||
.filter(ForwardEmail.gen_email_id == gen_email.id)
|
.filter(Contact.gen_email_id == gen_email.id)
|
||||||
.order_by(ForwardEmailLog.id.desc())
|
.order_by(ForwardEmailLog.id.desc())
|
||||||
.limit(PAGE_LIMIT)
|
.limit(PAGE_LIMIT)
|
||||||
.offset(page_id * PAGE_LIMIT)
|
.offset(page_id * PAGE_LIMIT)
|
||||||
|
@ -12,7 +12,7 @@ from app.log import LOG
|
|||||||
from app.models import (
|
from app.models import (
|
||||||
GenEmail,
|
GenEmail,
|
||||||
ClientUser,
|
ClientUser,
|
||||||
ForwardEmail,
|
Contact,
|
||||||
ForwardEmailLog,
|
ForwardEmailLog,
|
||||||
DeletedAlias,
|
DeletedAlias,
|
||||||
AliasGeneratorEnum,
|
AliasGeneratorEnum,
|
||||||
@ -202,11 +202,9 @@ def get_alias_info(
|
|||||||
aliases = {} # dict of alias and AliasInfo
|
aliases = {} # dict of alias and AliasInfo
|
||||||
|
|
||||||
q = (
|
q = (
|
||||||
db.session.query(GenEmail, ForwardEmail, ForwardEmailLog, Mailbox)
|
db.session.query(GenEmail, Contact, ForwardEmailLog, Mailbox)
|
||||||
.join(ForwardEmail, GenEmail.id == ForwardEmail.gen_email_id, isouter=True)
|
.join(Contact, GenEmail.id == Contact.gen_email_id, isouter=True)
|
||||||
.join(
|
.join(ForwardEmailLog, Contact.id == ForwardEmailLog.forward_id, isouter=True)
|
||||||
ForwardEmailLog, ForwardEmail.id == ForwardEmailLog.forward_id, isouter=True
|
|
||||||
)
|
|
||||||
.join(Mailbox, GenEmail.mailbox_id == Mailbox.id, isouter=True)
|
.join(Mailbox, GenEmail.mailbox_id == Mailbox.id, isouter=True)
|
||||||
.filter(GenEmail.user_id == user.id)
|
.filter(GenEmail.user_id == user.id)
|
||||||
.order_by(GenEmail.created_at.desc())
|
.order_by(GenEmail.created_at.desc())
|
||||||
|
@ -693,7 +693,7 @@ class ClientUser(db.Model, ModelMixin):
|
|||||||
return res
|
return res
|
||||||
|
|
||||||
|
|
||||||
class ForwardEmail(db.Model, ModelMixin):
|
class Contact(db.Model, ModelMixin):
|
||||||
"""
|
"""
|
||||||
Store configuration of sender (website-email) and alias.
|
Store configuration of sender (website-email) and alias.
|
||||||
"""
|
"""
|
||||||
@ -719,7 +719,7 @@ class ForwardEmail(db.Model, ModelMixin):
|
|||||||
# it has the prefix "reply+" to distinguish with other email
|
# it has the prefix "reply+" to distinguish with other email
|
||||||
reply_email = db.Column(db.String(512), nullable=False)
|
reply_email = db.Column(db.String(512), nullable=False)
|
||||||
|
|
||||||
gen_email = db.relationship(GenEmail, backref="forward_emails")
|
gen_email = db.relationship(GenEmail, backref="contacts")
|
||||||
|
|
||||||
def website_send_to(self):
|
def website_send_to(self):
|
||||||
"""return the email address with name.
|
"""return the email address with name.
|
||||||
@ -750,7 +750,7 @@ class ForwardEmail(db.Model, ModelMixin):
|
|||||||
|
|
||||||
class ForwardEmailLog(db.Model, ModelMixin):
|
class ForwardEmailLog(db.Model, ModelMixin):
|
||||||
forward_id = db.Column(
|
forward_id = db.Column(
|
||||||
db.ForeignKey(ForwardEmail.id, ondelete="cascade"), nullable=False
|
db.ForeignKey(Contact.id, ondelete="cascade"), nullable=False
|
||||||
)
|
)
|
||||||
|
|
||||||
# whether this is a reply
|
# whether this is a reply
|
||||||
@ -769,7 +769,7 @@ class ForwardEmailLog(db.Model, ModelMixin):
|
|||||||
)
|
)
|
||||||
|
|
||||||
refused_email = db.relationship("RefusedEmail")
|
refused_email = db.relationship("RefusedEmail")
|
||||||
forward = db.relationship(ForwardEmail)
|
forward = db.relationship(Contact)
|
||||||
|
|
||||||
|
|
||||||
class Subscription(db.Model, ModelMixin):
|
class Subscription(db.Model, ModelMixin):
|
||||||
|
8
cron.py
8
cron.py
@ -12,7 +12,7 @@ from app.models import (
|
|||||||
User,
|
User,
|
||||||
GenEmail,
|
GenEmail,
|
||||||
ForwardEmailLog,
|
ForwardEmailLog,
|
||||||
ForwardEmail,
|
Contact,
|
||||||
CustomDomain,
|
CustomDomain,
|
||||||
Client,
|
Client,
|
||||||
ManualSubscription,
|
ManualSubscription,
|
||||||
@ -119,9 +119,9 @@ def stats():
|
|||||||
LOG.d("total number alias %s", nb_gen_email)
|
LOG.d("total number alias %s", nb_gen_email)
|
||||||
|
|
||||||
# nb mails forwarded
|
# nb mails forwarded
|
||||||
q = db.session.query(ForwardEmailLog, ForwardEmail, GenEmail, User).filter(
|
q = db.session.query(ForwardEmailLog, Contact, GenEmail, User).filter(
|
||||||
ForwardEmailLog.forward_id == ForwardEmail.id,
|
ForwardEmailLog.forward_id == Contact.id,
|
||||||
ForwardEmail.gen_email_id == GenEmail.id,
|
Contact.gen_email_id == GenEmail.id,
|
||||||
GenEmail.user_id == User.id,
|
GenEmail.user_id == User.id,
|
||||||
)
|
)
|
||||||
for ie in IGNORED_EMAILS:
|
for ie in IGNORED_EMAILS:
|
||||||
|
@ -70,7 +70,7 @@ from app.extensions import db
|
|||||||
from app.log import LOG
|
from app.log import LOG
|
||||||
from app.models import (
|
from app.models import (
|
||||||
GenEmail,
|
GenEmail,
|
||||||
ForwardEmail,
|
Contact,
|
||||||
ForwardEmailLog,
|
ForwardEmailLog,
|
||||||
CustomDomain,
|
CustomDomain,
|
||||||
Directory,
|
Directory,
|
||||||
@ -207,21 +207,17 @@ def try_auto_create_catch_all_domain(alias: str) -> Optional[GenEmail]:
|
|||||||
return gen_email
|
return gen_email
|
||||||
|
|
||||||
|
|
||||||
def get_or_create_forward_email(
|
def get_or_create_contact(website_from_header: str, gen_email: GenEmail) -> Contact:
|
||||||
website_from_header: str, gen_email: GenEmail
|
|
||||||
) -> ForwardEmail:
|
|
||||||
"""
|
"""
|
||||||
website_from_header can be the full-form email, i.e. "First Last <email@example.com>"
|
website_from_header can be the full-form email, i.e. "First Last <email@example.com>"
|
||||||
"""
|
"""
|
||||||
_, website_email = parseaddr(website_from_header)
|
_, website_email = parseaddr(website_from_header)
|
||||||
forward_email = ForwardEmail.get_by(
|
contact = Contact.get_by(gen_email_id=gen_email.id, website_email=website_email)
|
||||||
gen_email_id=gen_email.id, website_email=website_email
|
if contact:
|
||||||
)
|
|
||||||
if forward_email:
|
|
||||||
# update the website_from if needed
|
# update the website_from if needed
|
||||||
if forward_email.website_from != website_from_header:
|
if contact.website_from != website_from_header:
|
||||||
LOG.d("Update From header for %s", forward_email)
|
LOG.d("Update From header for %s", contact)
|
||||||
forward_email.website_from = website_from_header
|
contact.website_from = website_from_header
|
||||||
db.session.commit()
|
db.session.commit()
|
||||||
else:
|
else:
|
||||||
LOG.debug(
|
LOG.debug(
|
||||||
@ -234,12 +230,12 @@ def get_or_create_forward_email(
|
|||||||
# not use while loop to avoid infinite loop
|
# not use while loop to avoid infinite loop
|
||||||
reply_email = f"reply+{random_string(30)}@{EMAIL_DOMAIN}"
|
reply_email = f"reply+{random_string(30)}@{EMAIL_DOMAIN}"
|
||||||
for _ in range(1000):
|
for _ in range(1000):
|
||||||
if not ForwardEmail.get_by(reply_email=reply_email):
|
if not Contact.get_by(reply_email=reply_email):
|
||||||
# found!
|
# found!
|
||||||
break
|
break
|
||||||
reply_email = f"reply+{random_string(30)}@{EMAIL_DOMAIN}"
|
reply_email = f"reply+{random_string(30)}@{EMAIL_DOMAIN}"
|
||||||
|
|
||||||
forward_email = ForwardEmail.create(
|
contact = Contact.create(
|
||||||
gen_email_id=gen_email.id,
|
gen_email_id=gen_email.id,
|
||||||
website_email=website_email,
|
website_email=website_email,
|
||||||
website_from=website_from_header,
|
website_from=website_from_header,
|
||||||
@ -247,7 +243,7 @@ def get_or_create_forward_email(
|
|||||||
)
|
)
|
||||||
db.session.commit()
|
db.session.commit()
|
||||||
|
|
||||||
return forward_email
|
return contact
|
||||||
|
|
||||||
|
|
||||||
def should_append_alias(msg, alias):
|
def should_append_alias(msg, alias):
|
||||||
@ -317,8 +313,8 @@ def handle_forward(envelope, smtp: SMTP, msg: Message, rcpt_to: str) -> str:
|
|||||||
LOG.d("Encrypt message using mailbox %s", mailbox)
|
LOG.d("Encrypt message using mailbox %s", mailbox)
|
||||||
msg = prepare_pgp_message(msg, mailbox.pgp_finger_print)
|
msg = prepare_pgp_message(msg, mailbox.pgp_finger_print)
|
||||||
|
|
||||||
forward_email = get_or_create_forward_email(msg["From"], gen_email)
|
contact = get_or_create_contact(msg["From"], gen_email)
|
||||||
forward_log = ForwardEmailLog.create(forward_id=forward_email.id)
|
forward_log = ForwardEmailLog.create(forward_id=contact.id)
|
||||||
|
|
||||||
if gen_email.enabled:
|
if gen_email.enabled:
|
||||||
# add custom header
|
# add custom header
|
||||||
@ -338,7 +334,7 @@ def handle_forward(envelope, smtp: SMTP, msg: Message, rcpt_to: str) -> str:
|
|||||||
+ (" - " if website_name else "")
|
+ (" - " if website_name else "")
|
||||||
+ website_email.replace("@", " at ")
|
+ website_email.replace("@", " at ")
|
||||||
)
|
)
|
||||||
from_header = formataddr((new_website_name, forward_email.reply_email))
|
from_header = formataddr((new_website_name, contact.reply_email))
|
||||||
add_or_replace_header(msg, "From", from_header)
|
add_or_replace_header(msg, "From", from_header)
|
||||||
LOG.d("new from header:%s", from_header)
|
LOG.d("new from header:%s", from_header)
|
||||||
|
|
||||||
@ -373,7 +369,7 @@ def handle_forward(envelope, smtp: SMTP, msg: Message, rcpt_to: str) -> str:
|
|||||||
# encode message raw directly instead
|
# encode message raw directly instead
|
||||||
msg_raw = msg.as_string().encode()
|
msg_raw = msg.as_string().encode()
|
||||||
smtp.sendmail(
|
smtp.sendmail(
|
||||||
forward_email.reply_email,
|
contact.reply_email,
|
||||||
mailbox_email,
|
mailbox_email,
|
||||||
msg_raw,
|
msg_raw,
|
||||||
envelope.mail_options,
|
envelope.mail_options,
|
||||||
@ -395,12 +391,12 @@ def handle_reply(envelope, smtp: SMTP, msg: Message, rcpt_to: str) -> str:
|
|||||||
LOG.warning(f"Reply email {reply_email} has wrong domain")
|
LOG.warning(f"Reply email {reply_email} has wrong domain")
|
||||||
return "550 wrong reply email"
|
return "550 wrong reply email"
|
||||||
|
|
||||||
forward_email = ForwardEmail.get_by(reply_email=reply_email)
|
contact = Contact.get_by(reply_email=reply_email)
|
||||||
if not forward_email:
|
if not contact:
|
||||||
LOG.warning(f"No such forward-email with {reply_email} as reply-email")
|
LOG.warning(f"No such forward-email with {reply_email} as reply-email")
|
||||||
return "550 wrong reply email"
|
return "550 wrong reply email"
|
||||||
|
|
||||||
alias: str = forward_email.gen_email.email
|
alias: str = contact.gen_email.email
|
||||||
alias_domain = alias[alias.find("@") + 1 :]
|
alias_domain = alias[alias.find("@") + 1 :]
|
||||||
|
|
||||||
# alias must end with one of the ALIAS_DOMAINS or custom-domain
|
# alias must end with one of the ALIAS_DOMAINS or custom-domain
|
||||||
@ -408,7 +404,7 @@ def handle_reply(envelope, smtp: SMTP, msg: Message, rcpt_to: str) -> str:
|
|||||||
if not CustomDomain.get_by(domain=alias_domain):
|
if not CustomDomain.get_by(domain=alias_domain):
|
||||||
return "550 alias unknown by SimpleLogin"
|
return "550 alias unknown by SimpleLogin"
|
||||||
|
|
||||||
gen_email = forward_email.gen_email
|
gen_email = contact.gen_email
|
||||||
user = gen_email.user
|
user = gen_email.user
|
||||||
mailbox_email = gen_email.mailbox_email()
|
mailbox_email = gen_email.mailbox_email()
|
||||||
|
|
||||||
@ -420,12 +416,12 @@ def handle_reply(envelope, smtp: SMTP, msg: Message, rcpt_to: str) -> str:
|
|||||||
LOG.error(
|
LOG.error(
|
||||||
"Bounce when sending to alias %s from %s, user %s",
|
"Bounce when sending to alias %s from %s, user %s",
|
||||||
alias,
|
alias,
|
||||||
forward_email.website_from,
|
contact.website_from,
|
||||||
gen_email.user,
|
gen_email.user,
|
||||||
)
|
)
|
||||||
|
|
||||||
handle_bounce(
|
handle_bounce(
|
||||||
alias, envelope, forward_email, gen_email, msg, smtp, user, mailbox_email
|
alias, envelope, contact, gen_email, msg, smtp, user, mailbox_email
|
||||||
)
|
)
|
||||||
return "550 ignored"
|
return "550 ignored"
|
||||||
|
|
||||||
@ -485,10 +481,10 @@ def handle_reply(envelope, smtp: SMTP, msg: Message, rcpt_to: str) -> str:
|
|||||||
# remove sender header if present as this could reveal user real email
|
# remove sender header if present as this could reveal user real email
|
||||||
delete_header(msg, "Sender")
|
delete_header(msg, "Sender")
|
||||||
|
|
||||||
add_or_replace_header(msg, "To", forward_email.website_email)
|
add_or_replace_header(msg, "To", contact.website_email)
|
||||||
|
|
||||||
# add List-Unsubscribe header
|
# add List-Unsubscribe header
|
||||||
unsubscribe_link = f"{URL}/dashboard/unsubscribe/{forward_email.gen_email_id}"
|
unsubscribe_link = f"{URL}/dashboard/unsubscribe/{contact.gen_email_id}"
|
||||||
add_or_replace_header(msg, "List-Unsubscribe", f"<{unsubscribe_link}>")
|
add_or_replace_header(msg, "List-Unsubscribe", f"<{unsubscribe_link}>")
|
||||||
add_or_replace_header(msg, "List-Unsubscribe-Post", "List-Unsubscribe=One-Click")
|
add_or_replace_header(msg, "List-Unsubscribe-Post", "List-Unsubscribe=One-Click")
|
||||||
|
|
||||||
@ -498,7 +494,7 @@ def handle_reply(envelope, smtp: SMTP, msg: Message, rcpt_to: str) -> str:
|
|||||||
LOG.d(
|
LOG.d(
|
||||||
"send email from %s to %s, mail_options:%s,rcpt_options:%s",
|
"send email from %s to %s, mail_options:%s,rcpt_options:%s",
|
||||||
alias,
|
alias,
|
||||||
forward_email.website_email,
|
contact.website_email,
|
||||||
envelope.mail_options,
|
envelope.mail_options,
|
||||||
envelope.rcpt_options,
|
envelope.rcpt_options,
|
||||||
)
|
)
|
||||||
@ -514,29 +510,23 @@ def handle_reply(envelope, smtp: SMTP, msg: Message, rcpt_to: str) -> str:
|
|||||||
msg_raw = msg.as_string().encode()
|
msg_raw = msg.as_string().encode()
|
||||||
smtp.sendmail(
|
smtp.sendmail(
|
||||||
alias,
|
alias,
|
||||||
forward_email.website_email,
|
contact.website_email,
|
||||||
msg_raw,
|
msg_raw,
|
||||||
envelope.mail_options,
|
envelope.mail_options,
|
||||||
envelope.rcpt_options,
|
envelope.rcpt_options,
|
||||||
)
|
)
|
||||||
|
|
||||||
ForwardEmailLog.create(forward_id=forward_email.id, is_reply=True)
|
ForwardEmailLog.create(forward_id=contact.id, is_reply=True)
|
||||||
db.session.commit()
|
db.session.commit()
|
||||||
|
|
||||||
return "250 Message accepted for delivery"
|
return "250 Message accepted for delivery"
|
||||||
|
|
||||||
|
|
||||||
def handle_bounce(
|
def handle_bounce(alias, envelope, contact, gen_email, msg, smtp, user, mailbox_email):
|
||||||
alias, envelope, forward_email, gen_email, msg, smtp, user, mailbox_email
|
fel: ForwardEmailLog = ForwardEmailLog.create(forward_id=contact.id, bounced=True)
|
||||||
):
|
|
||||||
fel: ForwardEmailLog = ForwardEmailLog.create(
|
|
||||||
forward_id=forward_email.id, bounced=True
|
|
||||||
)
|
|
||||||
db.session.commit()
|
db.session.commit()
|
||||||
|
|
||||||
nb_bounced = ForwardEmailLog.filter_by(
|
nb_bounced = ForwardEmailLog.filter_by(forward_id=contact.id, bounced=True).count()
|
||||||
forward_id=forward_email.id, bounced=True
|
|
||||||
).count()
|
|
||||||
disable_alias_link = f"{URL}/dashboard/unsubscribe/{gen_email.id}"
|
disable_alias_link = f"{URL}/dashboard/unsubscribe/{gen_email.id}"
|
||||||
|
|
||||||
# Store the bounced email
|
# Store the bounced email
|
||||||
@ -569,19 +559,19 @@ def handle_bounce(
|
|||||||
LOG.d(
|
LOG.d(
|
||||||
"Inform user %s about bounced email sent by %s to alias %s",
|
"Inform user %s about bounced email sent by %s to alias %s",
|
||||||
user,
|
user,
|
||||||
forward_email.website_from,
|
contact.website_from,
|
||||||
alias,
|
alias,
|
||||||
)
|
)
|
||||||
send_email(
|
send_email(
|
||||||
# use user mail here as only user is authenticated to see the refused email
|
# use user mail here as only user is authenticated to see the refused email
|
||||||
user.email,
|
user.email,
|
||||||
f"Email from {forward_email.website_from} to {alias} cannot be delivered to your inbox",
|
f"Email from {contact.website_from} to {alias} cannot be delivered to your inbox",
|
||||||
render(
|
render(
|
||||||
"transactional/bounced-email.txt",
|
"transactional/bounced-email.txt",
|
||||||
name=user.name,
|
name=user.name,
|
||||||
alias=alias,
|
alias=alias,
|
||||||
website_from=forward_email.website_from,
|
website_from=contact.website_from,
|
||||||
website_email=forward_email.website_email,
|
website_email=contact.website_email,
|
||||||
disable_alias_link=disable_alias_link,
|
disable_alias_link=disable_alias_link,
|
||||||
refused_email_url=refused_email_url,
|
refused_email_url=refused_email_url,
|
||||||
mailbox_email=mailbox_email,
|
mailbox_email=mailbox_email,
|
||||||
@ -590,8 +580,8 @@ def handle_bounce(
|
|||||||
"transactional/bounced-email.html",
|
"transactional/bounced-email.html",
|
||||||
name=user.name,
|
name=user.name,
|
||||||
alias=alias,
|
alias=alias,
|
||||||
website_from=forward_email.website_from,
|
website_from=contact.website_from,
|
||||||
website_email=forward_email.website_email,
|
website_email=contact.website_email,
|
||||||
disable_alias_link=disable_alias_link,
|
disable_alias_link=disable_alias_link,
|
||||||
refused_email_url=refused_email_url,
|
refused_email_url=refused_email_url,
|
||||||
mailbox_email=mailbox_email,
|
mailbox_email=mailbox_email,
|
||||||
@ -604,7 +594,7 @@ def handle_bounce(
|
|||||||
LOG.d(
|
LOG.d(
|
||||||
"Bounce happens again with alias %s from %s. Disable alias now ",
|
"Bounce happens again with alias %s from %s. Disable alias now ",
|
||||||
alias,
|
alias,
|
||||||
forward_email.website_from,
|
contact.website_from,
|
||||||
)
|
)
|
||||||
gen_email.enabled = False
|
gen_email.enabled = False
|
||||||
db.session.commit()
|
db.session.commit()
|
||||||
@ -612,13 +602,13 @@ def handle_bounce(
|
|||||||
send_email(
|
send_email(
|
||||||
# use user mail here as only user is authenticated to see the refused email
|
# use user mail here as only user is authenticated to see the refused email
|
||||||
user.email,
|
user.email,
|
||||||
f"Alias {alias} has been disabled due to second undelivered email from {forward_email.website_from}",
|
f"Alias {alias} has been disabled due to second undelivered email from {contact.website_from}",
|
||||||
render(
|
render(
|
||||||
"transactional/automatic-disable-alias.txt",
|
"transactional/automatic-disable-alias.txt",
|
||||||
name=user.name,
|
name=user.name,
|
||||||
alias=alias,
|
alias=alias,
|
||||||
website_from=forward_email.website_from,
|
website_from=contact.website_from,
|
||||||
website_email=forward_email.website_email,
|
website_email=contact.website_email,
|
||||||
refused_email_url=refused_email_url,
|
refused_email_url=refused_email_url,
|
||||||
mailbox_email=mailbox_email,
|
mailbox_email=mailbox_email,
|
||||||
),
|
),
|
||||||
@ -626,8 +616,8 @@ def handle_bounce(
|
|||||||
"transactional/automatic-disable-alias.html",
|
"transactional/automatic-disable-alias.html",
|
||||||
name=user.name,
|
name=user.name,
|
||||||
alias=alias,
|
alias=alias,
|
||||||
website_from=forward_email.website_from,
|
website_from=contact.website_from,
|
||||||
website_email=forward_email.website_email,
|
website_email=contact.website_email,
|
||||||
refused_email_url=refused_email_url,
|
refused_email_url=refused_email_url,
|
||||||
mailbox_email=mailbox_email,
|
mailbox_email=mailbox_email,
|
||||||
),
|
),
|
||||||
|
@ -4,7 +4,7 @@ from flask import url_for
|
|||||||
|
|
||||||
from app.config import EMAIL_DOMAIN, MAX_NB_EMAIL_FREE_PLAN, PAGE_LIMIT
|
from app.config import EMAIL_DOMAIN, MAX_NB_EMAIL_FREE_PLAN, PAGE_LIMIT
|
||||||
from app.extensions import db
|
from app.extensions import db
|
||||||
from app.models import User, ApiKey, GenEmail, ForwardEmail, ForwardEmailLog
|
from app.models import User, ApiKey, GenEmail, Contact, ForwardEmailLog
|
||||||
from app.utils import random_word
|
from app.utils import random_word
|
||||||
|
|
||||||
|
|
||||||
@ -128,7 +128,7 @@ def test_alias_activities(flask_client):
|
|||||||
db.session.commit()
|
db.session.commit()
|
||||||
|
|
||||||
# create some alias log
|
# create some alias log
|
||||||
forward_email = ForwardEmail.create(
|
contact = Contact.create(
|
||||||
website_email="marketing@example.com",
|
website_email="marketing@example.com",
|
||||||
reply_email="reply@a.b",
|
reply_email="reply@a.b",
|
||||||
gen_email_id=gen_email.id,
|
gen_email_id=gen_email.id,
|
||||||
@ -136,10 +136,10 @@ def test_alias_activities(flask_client):
|
|||||||
db.session.commit()
|
db.session.commit()
|
||||||
|
|
||||||
for _ in range(int(PAGE_LIMIT / 2)):
|
for _ in range(int(PAGE_LIMIT / 2)):
|
||||||
ForwardEmailLog.create(forward_id=forward_email.id, is_reply=True)
|
ForwardEmailLog.create(forward_id=contact.id, is_reply=True)
|
||||||
|
|
||||||
for _ in range(int(PAGE_LIMIT / 2) + 2):
|
for _ in range(int(PAGE_LIMIT / 2) + 2):
|
||||||
ForwardEmailLog.create(forward_id=forward_email.id, blocked=True)
|
ForwardEmailLog.create(forward_id=contact.id, blocked=True)
|
||||||
|
|
||||||
r = flask_client.get(
|
r = flask_client.get(
|
||||||
url_for("api.get_alias_activities", alias_id=gen_email.id, page_id=0),
|
url_for("api.get_alias_activities", alias_id=gen_email.id, page_id=0),
|
||||||
@ -200,14 +200,14 @@ def test_alias_contacts(flask_client):
|
|||||||
|
|
||||||
# create some alias log
|
# create some alias log
|
||||||
for i in range(PAGE_LIMIT + 1):
|
for i in range(PAGE_LIMIT + 1):
|
||||||
forward_email = ForwardEmail.create(
|
contact = Contact.create(
|
||||||
website_email=f"marketing-{i}@example.com",
|
website_email=f"marketing-{i}@example.com",
|
||||||
reply_email=f"reply-{i}@a.b",
|
reply_email=f"reply-{i}@a.b",
|
||||||
gen_email_id=gen_email.id,
|
gen_email_id=gen_email.id,
|
||||||
)
|
)
|
||||||
db.session.commit()
|
db.session.commit()
|
||||||
|
|
||||||
ForwardEmailLog.create(forward_id=forward_email.id, is_reply=True)
|
ForwardEmailLog.create(forward_id=contact.id, is_reply=True)
|
||||||
db.session.commit()
|
db.session.commit()
|
||||||
|
|
||||||
r = flask_client.get(
|
r = flask_client.get(
|
||||||
|
Loading…
Reference in New Issue
Block a user