add SPF check

This commit is contained in:
Son NK 2019-12-06 11:54:01 +01:00
parent 1598fd8f36
commit 6723487a23
3 changed files with 98 additions and 36 deletions

View File

@ -28,50 +28,81 @@
{% if not custom_domain.verified %}
<hr>
Please follow the following steps to set up your domain: <br>
<div class="mb-3">Please follow the following steps to set up your domain: </div>
<div>
<span class="badge badge-primary badge-pill mr-2">1</span>
Add the following MX DNS record to your domain
</div>
<div class="row">
<div class="col-1">
<span class="badge badge-primary badge-pill">1</span>
</div>
<div class="ml-6 mt-3">
{% for priority, email_server in EMAIL_SERVERS_WITH_PRIORITY %}
<div class="ml-3 text-info">
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">
<div class="col-11">
Add the following MX DNS record to your domain
{% for priority, email_server in EMAIL_SERVERS_WITH_PRIORITY %}
{{ custom_domain.domain }} IN MX {{ priority }} {{ email_server }}
<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 %}
</pre>
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>
<span class="badge badge-primary badge-pill mr-2">2</span>
Verify 👇🏽
</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>
<div class="ml-6 mt-3">
<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>
Please add the following TXT DNS record to your domain:
{% if custom_domain.id in errors %}
<div class="text-danger">
{{ errors.get(custom_domain.id) }}
<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>
{% endif %}
As the change could take up to 24 hours, do not hesitate to come back to this page and verify again.
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>

View File

@ -5,7 +5,7 @@ from wtforms import StringField, validators
from app.config import EMAIL_SERVERS_WITH_PRIORITY, EMAIL_SERVERS
from app.dashboard.base import dashboard_bp
from app.dns_utils import get_mx_domains
from app.dns_utils import get_mx_domains, get_spf_domain
from app.email_utils import notify_admin
from app.extensions import db
from app.models import CustomDomain
@ -75,11 +75,17 @@ def custom_domain():
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 {mx_domains}"
] = 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",

View File

@ -11,3 +11,28 @@ def get_mx_domains(hostname) -> [str]:
ret.append(r)
return ret
_include_spf = "include:"
def get_spf_domain(hostname) -> [str]:
"""return all domains listed in *include:*"""
try:
answers = dns.resolver.query(hostname, "TXT")
except dns.resolver.NoAnswer:
return []
ret = []
for a in answers: # type: dns.rdtypes.ANY.TXT.TXT
for record in a.strings:
record = record.decode() # record is bytes
if record.startswith("v=spf1"):
parts = record.split(" ")
for part in parts:
if part.startswith(_include_spf):
ret.append(part[part.find(_include_spf) + len(_include_spf) :])
return ret