diff --git a/app/dashboard/templates/dashboard/custom_domain.html b/app/dashboard/templates/dashboard/custom_domain.html index 1c7db8b1..10626116 100644 --- a/app/dashboard/templates/dashboard/custom_domain.html +++ b/app/dashboard/templates/dashboard/custom_domain.html @@ -28,50 +28,81 @@ {% if not custom_domain.verified %}
- Please follow the following steps to set up your domain:
+
Please follow the following steps to set up your domain:
-
- 1 - Add the following MX DNS record to your domain -
+
+
+ 1 +
-
- {% for priority, email_server in EMAIL_SERVERS_WITH_PRIORITY %} -
- Domain: {{ custom_domain.domain }}
- Priority: 10
- Target: {{ email_server }}
-
- {% endfor %} - - Or if you edit your DNS record in text format, use the following code:
- -
+                
+ 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 }} +
+ Domain: {{ custom_domain.domain }}
+ Priority: 10
+ Target: {{ email_server }}
+
{% endfor %} -
+ + Or if you edit your DNS record in text format, use the following code:
+ +
{% for priority, email_server in EMAIL_SERVERS_WITH_PRIORITY %}{{ custom_domain.domain }} IN MX {{ priority }} {{ email_server }}
{% endfor %}
+
-
- 2 - Verify 👇🏽 -
+
+
2
+
+ [Optional] + Setup + SPF record. + This can avoid emails forwarded to your personal inbox classified as spam.
+ 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 + Whitelist domain
-
-
- - - -
+ Please add the following TXT DNS record to your domain: - {% if custom_domain.id in errors %} -
- {{ errors.get(custom_domain.id) }} +
+ Domain: {{ custom_domain.domain }}
+ Value: + + v=spf1 + {% for priority, email_server in EMAIL_SERVERS_WITH_PRIORITY %} + include:{{ email_server[:-1] }} + {% endfor %} -all +
- {% 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:
+ +
{{ custom_domain.domain }} IN TXT "v=spf1 {% for priority, email_server in EMAIL_SERVERS_WITH_PRIORITY %}include:{{ email_server[:-1] }} {% endfor %}-all"
+
+
+ +
+
+ 3 +
+ +
+ Verify 👇🏽 +
+ + + +
+ + {% if custom_domain.id in errors %} +
+ {{ errors.get(custom_domain.id) }} +
+ {% endif %} + + As the change could take up to 24 hours, do not hesitate to come back to this page and verify again. +
{% endif %}
diff --git a/app/dashboard/views/custom_domain.py b/app/dashboard/views/custom_domain.py index 149bac1d..aacc00e7 100644 --- a/app/dashboard/views/custom_domain.py +++ b/app/dashboard/views/custom_domain.py @@ -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", diff --git a/app/dns_utils.py b/app/dns_utils.py index 3fe5512f..00614246 100644 --- a/app/dns_utils.py +++ b/app/dns_utils.py @@ -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