move domain validation (mx, spf, mx) to domain detail page
This commit is contained in:
parent
34faafe25e
commit
8dcb8dd249
|
@ -10,4 +10,5 @@ from .views import (
|
|||
custom_domain,
|
||||
alias_contact_manager,
|
||||
mfa_setup,
|
||||
domain_detail,
|
||||
)
|
||||
|
|
|
@ -24,100 +24,7 @@
|
|||
<span class="font-weight-bold">{{ custom_domain.nb_alias() }}</span> aliases.
|
||||
</h6>
|
||||
|
||||
{% if not custom_domain.verified %}
|
||||
<hr>
|
||||
<div class="mb-3">Please follow the following steps to set up your domain: </div>
|
||||
|
||||
<div class="row">
|
||||
<div class="col-1">
|
||||
<span class="badge badge-primary badge-pill">1</span>
|
||||
</div>
|
||||
|
||||
<div class="col-11">
|
||||
Add the following MX DNS record to your domain
|
||||
{% for priority, email_server in EMAIL_SERVERS_WITH_PRIORITY %}
|
||||
<div class="ml-2 mb-3 p-3" style="background-color: #eee">
|
||||
Domain: <em>{{ custom_domain.domain }}</em> <br>
|
||||
Priority: 10 <br>
|
||||
Target: <em>{{ email_server }}</em> <br>
|
||||
</div>
|
||||
{% endfor %}
|
||||
|
||||
Or if you edit your DNS record in text format, use the following code: <br>
|
||||
|
||||
<pre class="ml-3">{% for priority, email_server in EMAIL_SERVERS_WITH_PRIORITY %}{{ custom_domain.domain }} IN MX {{ priority }} {{ email_server }}<br>{% endfor %}</pre>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="row">
|
||||
<div class="col-1"><span class="badge badge-primary badge-pill">2</span></div>
|
||||
<div class="col-11">
|
||||
<span class="font-weight-bold">[Optional]</span>
|
||||
Setup <a href="https://en.wikipedia.org/wiki/Sender_Policy_Framework" target="_blank">
|
||||
SPF <i class="fe fe-external-link"></i></a> record.
|
||||
This can avoid emails forwarded to your personal inbox classified as spam. <br>
|
||||
Please note that some email providers can still classify these forwards as spam, in this case
|
||||
do not hesitate to create rules to avoid these emails mistakenly gone into spam.
|
||||
You can find how to whitelist a domain on
|
||||
<a href="https://www.simplelogin.io/help" target="_blank">Whitelist domain<i class="fe fe-external-link"></i></a><br>
|
||||
|
||||
Please add the following TXT DNS record to your domain:
|
||||
|
||||
<div class="ml-3 mb-2 p-3" style="background-color: #eee">
|
||||
Domain: <em>{{ custom_domain.domain }}</em> <br>
|
||||
Value:
|
||||
<em>
|
||||
v=spf1
|
||||
{% for priority, email_server in EMAIL_SERVERS_WITH_PRIORITY %}
|
||||
include:{{ email_server[:-1] }}
|
||||
{% endfor %} -all
|
||||
</em>
|
||||
</div>
|
||||
|
||||
Or if you edit your DNS record in text format, use the following code: <br>
|
||||
|
||||
<pre class="ml-3">{{ custom_domain.domain }} IN TXT "v=spf1 {% for priority, email_server in EMAIL_SERVERS_WITH_PRIORITY %}include:{{ email_server[:-1] }} {% endfor %}-all"</pre>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="row">
|
||||
<div class="col-1">
|
||||
<span class="badge badge-primary badge-pill mr-2">3</span>
|
||||
</div>
|
||||
|
||||
<div class="col-11">
|
||||
Verify 👇🏽
|
||||
<form method="post">
|
||||
<input type="hidden" name="form-name" value="check-domain">
|
||||
<input type="hidden" name="custom-domain-id" value="{{ custom_domain.id }}">
|
||||
<button type="submit" class="btn btn-primary">Verify</button>
|
||||
</form>
|
||||
|
||||
{% if custom_domain.id in errors %}
|
||||
<div class="text-danger">
|
||||
{{ errors.get(custom_domain.id) }}
|
||||
</div>
|
||||
{% endif %}
|
||||
|
||||
As the change could take up to 24 hours, do not hesitate to come back to this page and verify again.
|
||||
</div>
|
||||
</div>
|
||||
{% endif %}
|
||||
</div>
|
||||
|
||||
<div class="card-footer">
|
||||
<div class="row">
|
||||
<div class="col">
|
||||
<form method="post">
|
||||
<input type="hidden" name="form-name" value="delete">
|
||||
<input type="hidden" name="custom-domain-id" value="{{ custom_domain.id }}">
|
||||
<span class="card-link btn btn-link float-right delete-custom-domain">
|
||||
Delete
|
||||
</span>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<a href="{{ url_for('dashboard.domain_detail', custom_domain_id=custom_domain.id) }}">Details ➡</a>
|
||||
</div>
|
||||
</div>
|
||||
{% endfor %}
|
||||
|
|
|
@ -0,0 +1,203 @@
|
|||
{% extends 'default.html' %}
|
||||
|
||||
{% block title %}
|
||||
{{ custom_domain.domain }}
|
||||
{% endblock %}
|
||||
|
||||
{% block head %}
|
||||
{% endblock %}
|
||||
|
||||
{% block default_content %}
|
||||
<div class="bg-white p-4" style="max-width: 60rem; margin: auto">
|
||||
<h1 class="h3"> {{ custom_domain.domain }} </h1>
|
||||
<div class="">Please follow the steps below to set up your domain.</div>
|
||||
|
||||
<div class="small-text mb-5">
|
||||
DNS changes could take up to 24 hours to propagate. In practice, it's a lot faster though (~1
|
||||
minute or in our experience).
|
||||
</div>
|
||||
|
||||
<div>
|
||||
<div class="font-weight-bold">1. MX record
|
||||
{% if custom_domain.verified %} ✅ {% else %} 🚫{% endif %}
|
||||
</div>
|
||||
|
||||
<div class="mb-2">Add the following MX DNS record to your domain</div>
|
||||
|
||||
{% for priority, email_server in EMAIL_SERVERS_WITH_PRIORITY %}
|
||||
<div class="mb-3 p-3" style="background-color: #eee">
|
||||
Domain: <em>{{ custom_domain.domain }}</em> <br>
|
||||
Priority: 10 <br>
|
||||
Target: <em>{{ email_server }}</em> <br>
|
||||
</div>
|
||||
{% endfor %}
|
||||
|
||||
<form method="post">
|
||||
<input type="hidden" name="form-name" value="check-mx">
|
||||
{% if custom_domain.verified %}
|
||||
<button type="submit" class="btn btn-outline-primary">
|
||||
Re-verify
|
||||
</button>
|
||||
{% else %}
|
||||
<button type="submit" class="btn btn-primary">
|
||||
Verify
|
||||
</button>
|
||||
{% endif %}
|
||||
</form>
|
||||
|
||||
{% if not mx_ok %}
|
||||
<div class="text-danger mt-4">
|
||||
Your DNS is not correctly set. The MX record we obtain is:
|
||||
<div class="mb-3 p-3" style="background-color: #eee">
|
||||
{% for r in mx_errors %}
|
||||
{{ r }} <br>
|
||||
{% endfor %}
|
||||
</div>
|
||||
{% if custom_domain.verified %}
|
||||
Please make sure to fix this ASAP - your aliases might not work properly.
|
||||
{% endif %}
|
||||
</div>
|
||||
{% endif %}
|
||||
</div>
|
||||
|
||||
<hr>
|
||||
|
||||
<div>
|
||||
<div class="font-weight-bold">2. SPF (Optional)
|
||||
{% if custom_domain.spf_verified %} ✅ {% else %} 🚫{% endif %}
|
||||
</div>
|
||||
|
||||
<div>
|
||||
SPF <a href="https://en.wikipedia.org/wiki/Sender_Policy_Framework" target="_blank">(Wikipedia↗)</a> is an email
|
||||
authentication method
|
||||
designed to detect forging sender addresses during the delivery of the email. <br>
|
||||
Setting up SPF is highly recommended to reduce the chance your emails ending up in the recipient's Spam folder.
|
||||
</div>
|
||||
|
||||
<div class="mb-2">Add the following TXT DNS record to your domain</div>
|
||||
|
||||
<div class="mb-2 p-3" style="background-color: #eee">
|
||||
Domain: <em>{{ custom_domain.domain }}</em> <br>
|
||||
Value:
|
||||
<em>
|
||||
{{ spf_record }}
|
||||
</em>
|
||||
</div>
|
||||
|
||||
<form method="post">
|
||||
<input type="hidden" name="form-name" value="check-spf">
|
||||
{% if custom_domain.spf_verified %}
|
||||
<button type="submit" class="btn btn-outline-primary">
|
||||
Re-verify
|
||||
</button>
|
||||
{% else %}
|
||||
<button type="submit" class="btn btn-primary">
|
||||
Verify
|
||||
</button>
|
||||
{% endif %}
|
||||
</form>
|
||||
|
||||
{% if not spf_ok %}
|
||||
<div class="text-danger mt-4">
|
||||
Your DNS is not correctly set. The TXT record we obtain is:
|
||||
<div class="mb-3 p-3" style="background-color: #eee">
|
||||
{% for r in spf_errors %}
|
||||
{{ r }} <br>
|
||||
{% endfor %}
|
||||
</div>
|
||||
{% if custom_domain.spf_verified %}
|
||||
Without SPF setup, emails you sent from your alias might end up in Spam/Junk folder.
|
||||
{% endif %}
|
||||
</div>
|
||||
{% endif %}
|
||||
</div>
|
||||
|
||||
<hr>
|
||||
|
||||
<div>
|
||||
<div class="font-weight-bold">3. DKIM (Optional)
|
||||
{% if custom_domain.dkim_verified %} ✅ {% else %} 🚫{% endif %}
|
||||
</div>
|
||||
|
||||
<div>
|
||||
DKIM <a href="https://en.wikipedia.org/wiki/DomainKeys_Identified_Mail" target="_blank">(Wikipedia↗)</a> is an
|
||||
email
|
||||
authentication method
|
||||
designed to avoid email spoofing. <br>
|
||||
Setting up DKIM is highly recommended to reduce the chance your emails ending up in the recipient's Spam folder.
|
||||
</div>
|
||||
|
||||
<div class="mb-2">Add the following TXT DNS record to your domain</div>
|
||||
|
||||
<div class="mb-2 p-3" style="background-color: #eee">
|
||||
Domain: <em>dkim._domainkey.{{ custom_domain.domain }}</em> <br>
|
||||
Value:
|
||||
<em style="overflow-wrap: break-word">
|
||||
{{ dkim_record }}
|
||||
</em>
|
||||
</div>
|
||||
|
||||
<form method="post">
|
||||
<input type="hidden" name="form-name" value="check-dkim">
|
||||
{% if custom_domain.dkim_verified %}
|
||||
<button type="submit" class="btn btn-outline-primary">
|
||||
Re-verify
|
||||
</button>
|
||||
{% else %}
|
||||
<button type="submit" class="btn btn-primary">
|
||||
Verify
|
||||
</button>
|
||||
{% endif %}
|
||||
</form>
|
||||
|
||||
{% if not dkim_ok %}
|
||||
<div class="text-danger mt-4">
|
||||
Your DNS is not correctly set.
|
||||
{% if dkim_errors %}
|
||||
The TXT record we obtain for
|
||||
<em>dkim._domainkey.{{ custom_domain.domain }}</em> is:
|
||||
|
||||
<div class="mb-3 p-3" style="background-color: #eee">
|
||||
{% for r in dkim_errors %}
|
||||
{{ r }} <br>
|
||||
{% endfor %}
|
||||
</div>
|
||||
{% endif %}
|
||||
|
||||
{% if custom_domain.dkim_verified %}
|
||||
Without DKIM setup, emails you sent from your alias might end up in Spam/Junk folder.
|
||||
{% endif %}
|
||||
</div>
|
||||
{% endif %}
|
||||
</div>
|
||||
|
||||
<hr>
|
||||
<h3 class="mb-0">Delete Domain</h3>
|
||||
<div class="small-text mb-3">Please note that this operation is irreversible.
|
||||
All aliases associated with this domain will be also deleted
|
||||
</div>
|
||||
|
||||
<form method="post">
|
||||
<input type="hidden" name="form-name" value="delete">
|
||||
<span class="delete-custom-domain btn btn-outline-danger">Delete domain</span>
|
||||
</form>
|
||||
|
||||
</div>
|
||||
{% endblock %}
|
||||
|
||||
{% block script %}
|
||||
<script>
|
||||
$(".delete-custom-domain").on("click", function (e) {
|
||||
notie.confirm({
|
||||
text: "All aliases associated with <b>{{ custom_domain.domain }}</b> will be also deleted, " +
|
||||
" please confirm.",
|
||||
cancelCallback: () => {
|
||||
// nothing to do
|
||||
},
|
||||
submitCallback: () => {
|
||||
$(this).closest("form").submit();
|
||||
}
|
||||
});
|
||||
});
|
||||
</script>
|
||||
{% endblock %}
|
|
@ -3,9 +3,8 @@ from flask_login import login_required, current_user
|
|||
from flask_wtf import FlaskForm
|
||||
from wtforms import StringField, validators
|
||||
|
||||
from app.config import EMAIL_SERVERS_WITH_PRIORITY, EMAIL_SERVERS
|
||||
from app.config import EMAIL_SERVERS_WITH_PRIORITY
|
||||
from app.dashboard.base import dashboard_bp
|
||||
from app.dns_utils import get_mx_domains, get_spf_domain
|
||||
from app.extensions import db
|
||||
from app.models import CustomDomain
|
||||
|
||||
|
@ -30,25 +29,7 @@ def custom_domain():
|
|||
errors = {}
|
||||
|
||||
if request.method == "POST":
|
||||
if request.form.get("form-name") == "delete":
|
||||
custom_domain_id = request.form.get("custom-domain-id")
|
||||
custom_domain = CustomDomain.get(custom_domain_id)
|
||||
|
||||
if not custom_domain:
|
||||
flash("Unknown error. Refresh the page", "warning")
|
||||
return redirect(url_for("dashboard.custom_domain"))
|
||||
elif custom_domain.user_id != current_user.id:
|
||||
flash("You cannot delete this domain", "warning")
|
||||
return redirect(url_for("dashboard.custom_domain"))
|
||||
|
||||
name = custom_domain.domain
|
||||
CustomDomain.delete(custom_domain_id)
|
||||
db.session.commit()
|
||||
flash(f"Domain {name} has been deleted successfully", "success")
|
||||
|
||||
return redirect(url_for("dashboard.custom_domain"))
|
||||
|
||||
elif request.form.get("form-name") == "create":
|
||||
if request.form.get("form-name") == "create":
|
||||
if new_custom_domain_form.validate():
|
||||
new_custom_domain = CustomDomain.create(
|
||||
domain=new_custom_domain_form.domain.data, user_id=current_user.id
|
||||
|
@ -60,39 +41,11 @@ def custom_domain():
|
|||
"success",
|
||||
)
|
||||
|
||||
return redirect(url_for("dashboard.custom_domain"))
|
||||
elif request.form.get("form-name") == "check-domain":
|
||||
custom_domain_id = request.form.get("custom-domain-id")
|
||||
custom_domain = CustomDomain.get(custom_domain_id)
|
||||
|
||||
if not custom_domain:
|
||||
flash("Unknown error. Refresh the page", "warning")
|
||||
return redirect(url_for("dashboard.custom_domain"))
|
||||
elif custom_domain.user_id != current_user.id:
|
||||
flash("You cannot delete this domain", "warning")
|
||||
return redirect(url_for("dashboard.custom_domain"))
|
||||
else:
|
||||
spf_domains = get_spf_domain(custom_domain.domain)
|
||||
for email_server in EMAIL_SERVERS:
|
||||
email_server = email_server[:-1] # remove the trailing .
|
||||
if email_server not in spf_domains:
|
||||
flash(
|
||||
f"{email_server} is not included in your SPF record.",
|
||||
"warning",
|
||||
)
|
||||
|
||||
mx_domains = get_mx_domains(custom_domain.domain)
|
||||
if mx_domains != EMAIL_SERVERS:
|
||||
errors[
|
||||
custom_domain.id
|
||||
] = f"""Your DNS is not correctly set. The MX record we obtain is: {",".join(mx_domains)}"""
|
||||
else:
|
||||
flash(
|
||||
"Your domain is verified. Now it can be used to create custom alias",
|
||||
"success",
|
||||
return redirect(
|
||||
url_for(
|
||||
"dashboard.domain_detail", custom_domain_id=new_custom_domain.id
|
||||
)
|
||||
custom_domain.verified = True
|
||||
db.session.commit()
|
||||
)
|
||||
|
||||
return render_template(
|
||||
"dashboard/custom_domain.html",
|
||||
|
|
|
@ -0,0 +1,118 @@
|
|||
from flask import render_template, request, redirect, url_for, flash
|
||||
from flask_login import login_required, current_user
|
||||
|
||||
from app.config import EMAIL_SERVERS_WITH_PRIORITY, EMAIL_SERVERS, DKIM_DNS_VALUE
|
||||
from app.dashboard.base import dashboard_bp
|
||||
from app.dns_utils import (
|
||||
get_mx_domains,
|
||||
get_spf_domain,
|
||||
get_dkim_record,
|
||||
get_txt_record,
|
||||
)
|
||||
from app.extensions import db
|
||||
from app.models import CustomDomain
|
||||
|
||||
|
||||
@dashboard_bp.route("/domains/<int:custom_domain_id>", methods=["GET", "POST"])
|
||||
@login_required
|
||||
def domain_detail(custom_domain_id):
|
||||
# only premium user can see custom domain
|
||||
if not current_user.is_premium():
|
||||
flash("Only premium user can add custom domains", "warning")
|
||||
return redirect(url_for("dashboard.index"))
|
||||
|
||||
custom_domain = CustomDomain.get(custom_domain_id)
|
||||
if not custom_domain or custom_domain.user_id != current_user.id:
|
||||
flash("You cannot see this page", "warning")
|
||||
return redirect(url_for("dashboard.index"))
|
||||
|
||||
mx_ok = spf_ok = dkim_ok = True
|
||||
mx_errors = spf_errors = dkim_errors = []
|
||||
|
||||
if request.method == "POST":
|
||||
if request.form.get("form-name") == "check-mx":
|
||||
mx_domains = get_mx_domains(custom_domain.domain)
|
||||
|
||||
if mx_domains != EMAIL_SERVERS:
|
||||
mx_ok = False
|
||||
mx_errors = get_mx_domains(custom_domain.domain, keep_priority=True)
|
||||
else:
|
||||
flash(
|
||||
"Your domain is verified. Now it can be used to create custom alias",
|
||||
"success",
|
||||
)
|
||||
custom_domain.verified = True
|
||||
db.session.commit()
|
||||
return redirect(
|
||||
url_for(
|
||||
"dashboard.domain_detail", custom_domain_id=custom_domain.id
|
||||
)
|
||||
)
|
||||
elif request.form.get("form-name") == "check-spf":
|
||||
spf_domains = get_spf_domain(custom_domain.domain)
|
||||
for email_server in EMAIL_SERVERS:
|
||||
email_server = email_server[:-1] # remove the trailing .
|
||||
if email_server not in spf_domains:
|
||||
flash(
|
||||
f"{email_server} is not included in your SPF record.", "warning"
|
||||
)
|
||||
spf_ok = False
|
||||
|
||||
if spf_ok:
|
||||
custom_domain.spf_verified = True
|
||||
db.session.commit()
|
||||
flash("The SPF is setup correctly", "success")
|
||||
return redirect(
|
||||
url_for(
|
||||
"dashboard.domain_detail", custom_domain_id=custom_domain.id
|
||||
)
|
||||
)
|
||||
else:
|
||||
spf_errors = get_txt_record(custom_domain.domain)
|
||||
|
||||
elif request.form.get("form-name") == "check-dkim":
|
||||
dkim_record = get_dkim_record(custom_domain.domain)
|
||||
correct_dkim_record = f"v=DKIM1; k=rsa; p={DKIM_DNS_VALUE}"
|
||||
if dkim_record == correct_dkim_record:
|
||||
flash("The DKIM is setup correctly.", "success")
|
||||
custom_domain.dkim_verified = True
|
||||
db.session.commit()
|
||||
|
||||
return redirect(
|
||||
url_for(
|
||||
"dashboard.domain_detail", custom_domain_id=custom_domain.id
|
||||
)
|
||||
)
|
||||
else:
|
||||
dkim_ok = False
|
||||
dkim_errors = get_txt_record(f"dkim._domainkey.{custom_domain.domain}")
|
||||
|
||||
elif request.form.get("form-name") == "delete":
|
||||
name = custom_domain.domain
|
||||
CustomDomain.delete(custom_domain_id)
|
||||
db.session.commit()
|
||||
flash(f"Domain {name} has been deleted successfully", "success")
|
||||
|
||||
return redirect(url_for("dashboard.custom_domain"))
|
||||
|
||||
spf_include_records = []
|
||||
for priority, email_server in EMAIL_SERVERS_WITH_PRIORITY:
|
||||
spf_include_records.append(f"include:{email_server[:-1]}")
|
||||
|
||||
spf_record = f"v=spf1 {' '.join(spf_include_records)} -all"
|
||||
|
||||
dkim_record = f"v=DKIM1; k=rsa; p={DKIM_DNS_VALUE}"
|
||||
|
||||
return render_template(
|
||||
"dashboard/domain_detail.html",
|
||||
custom_domain=custom_domain,
|
||||
EMAIL_SERVERS_WITH_PRIORITY=EMAIL_SERVERS_WITH_PRIORITY,
|
||||
spf_record=spf_record,
|
||||
dkim_record=dkim_record,
|
||||
mx_errors=mx_errors,
|
||||
mx_ok=mx_ok,
|
||||
spf_errors=spf_errors,
|
||||
spf_ok=spf_ok,
|
||||
dkim_errors=dkim_errors,
|
||||
dkim_ok=dkim_ok,
|
||||
)
|
Loading…
Reference in New Issue