예제 #1
0
def get_mx_domain_list(domain) -> [str]:
    """return list of MX domains for a given email.
    domain name ends *without* a dot (".") at the end.
    """
    priority_domains = get_mx_domains(domain)

    return [d[:-1] for _, d in priority_domains]
예제 #2
0
def test_get_mx_domains():
    r = get_mx_domains(_DOMAIN)

    assert len(r) > 0

    for x in r:
        assert x[0] > 0
        assert x[1]
예제 #3
0
def check_custom_domain():
    LOG.d("Check verified domain for DNS issues")

    for custom_domain in CustomDomain.query.filter_by(
        verified=True
    ):  # type: CustomDomain
        mx_domains = get_mx_domains(custom_domain.domain)

        if sorted(mx_domains) != sorted(EMAIL_SERVERS_WITH_PRIORITY):
            user = custom_domain.user
            LOG.warning(
                "The MX record is not correctly set for %s %s %s",
                custom_domain,
                user,
                mx_domains,
            )

            custom_domain.nb_failed_checks += 1

            # send alert if fail for 5 consecutive days
            if custom_domain.nb_failed_checks > 5:
                domain_dns_url = f"{URL}/dashboard/domains/{custom_domain.id}/dns"
                LOG.warning(
                    "Alert domain MX check fails %s about %s", user, custom_domain
                )
                send_email_with_rate_control(
                    user,
                    AlERT_WRONG_MX_RECORD_CUSTOM_DOMAIN,
                    user.email,
                    f"Please update {custom_domain.domain} DNS on SimpleLogin",
                    render(
                        "transactional/custom-domain-dns-issue.txt",
                        custom_domain=custom_domain,
                        domain_dns_url=domain_dns_url,
                    ),
                    render(
                        "transactional/custom-domain-dns-issue.html",
                        custom_domain=custom_domain,
                        domain_dns_url=domain_dns_url,
                    ),
                    max_nb_alert=1,
                    nb_day=30,
                )
                # reset checks
                custom_domain.nb_failed_checks = 0
        else:
            # reset checks
            custom_domain.nb_failed_checks = 0

        db.session.commit()
예제 #4
0
def check_custom_domain():
    LOG.d("Check verified domain for DNS issues")

    for custom_domain in CustomDomain.query.filter(
            CustomDomain.verified == True):
        mx_domains = get_mx_domains(custom_domain.domain)

        if sorted(mx_domains) != sorted(EMAIL_SERVERS_WITH_PRIORITY):
            user = custom_domain.user
            LOG.warning(
                "The MX record is not correctly set for %s %s %s",
                custom_domain,
                user,
                mx_domains,
            )

            domain_dns_url = f"{URL}/dashboard/domains/{custom_domain.id}/dns"

            send_email_with_rate_control(
                user,
                AlERT_WRONG_MX_RECORD_CUSTOM_DOMAIN,
                user.email,
                f"Please update {custom_domain.domain} DNS on SimpleLogin",
                render(
                    "transactional/custom-domain-dns-issue.txt",
                    custom_domain=custom_domain,
                    name=user.name or "",
                    domain_dns_url=domain_dns_url,
                ),
                render(
                    "transactional/custom-domain-dns-issue.html",
                    custom_domain=custom_domain,
                    name=user.name or "",
                    domain_dns_url=domain_dns_url,
                ),
                max_nb_alert=1,
                nb_day=30,
            )
예제 #5
0
def check_single_custom_domain(custom_domain):
    mx_domains = get_mx_domains(custom_domain.domain)
    if not is_mx_equivalent(mx_domains, EMAIL_SERVERS_WITH_PRIORITY):
        user = custom_domain.user
        LOG.w(
            "The MX record is not correctly set for %s %s %s",
            custom_domain,
            user,
            mx_domains,
        )

        custom_domain.nb_failed_checks += 1

        # send alert if fail for 5 consecutive days
        if custom_domain.nb_failed_checks > 5:
            domain_dns_url = f"{URL}/dashboard/domains/{custom_domain.id}/dns"
            LOG.w("Alert domain MX check fails %s about %s", user,
                  custom_domain)
            send_email_with_rate_control(
                user,
                AlERT_WRONG_MX_RECORD_CUSTOM_DOMAIN,
                user.email,
                f"Please update {custom_domain.domain} DNS on SimpleLogin",
                render(
                    "transactional/custom-domain-dns-issue.txt.jinja2",
                    custom_domain=custom_domain,
                    domain_dns_url=domain_dns_url,
                ),
                max_nb_alert=1,
                nb_day=30,
                retries=3,
            )
            # reset checks
            custom_domain.nb_failed_checks = 0
    else:
        # reset checks
        custom_domain.nb_failed_checks = 0
    Session.commit()
예제 #6
0
def domain_detail_dns(custom_domain_id):
    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"))

    spf_record = f"v=spf1 include:{EMAIL_DOMAIN} -all"

    # hardcode the DKIM selector here
    dkim_cname = f"dkim._domainkey.{EMAIL_DOMAIN}"

    dmarc_record = "v=DMARC1; p=quarantine; pct=100; adkim=s; aspf=s"

    mx_ok = spf_ok = dkim_ok = dmarc_ok = True
    mx_errors = spf_errors = dkim_errors = dmarc_errors = []

    if request.method == "POST":
        if request.form.get("form-name") == "check-mx":
            mx_domains = get_mx_domains(custom_domain.domain)

            if sorted(mx_domains) != sorted(EMAIL_SERVERS_WITH_PRIORITY):
                flash("The MX record is not correctly set", "warning")

                mx_ok = False
                # build mx_errors to show to user
                mx_errors = [
                    f"{priority} {domain}" for (priority, domain) in mx_domains
                ]
            else:
                flash(
                    "Your domain can start receiving emails. You can now use it to create alias",
                    "success",
                )
                custom_domain.verified = True
                db.session.commit()
                return redirect(
                    url_for("dashboard.domain_detail_dns",
                            custom_domain_id=custom_domain.id))
        elif request.form.get("form-name") == "check-spf":
            spf_domains = get_spf_domain(custom_domain.domain)
            if EMAIL_DOMAIN in spf_domains:
                custom_domain.spf_verified = True
                db.session.commit()
                flash("SPF is setup correctly", "success")
                return redirect(
                    url_for("dashboard.domain_detail_dns",
                            custom_domain_id=custom_domain.id))
            else:
                custom_domain.spf_verified = False
                db.session.commit()
                flash(
                    f"SPF: {EMAIL_DOMAIN} is not included in your SPF record.",
                    "warning",
                )
                spf_ok = False
                spf_errors = get_txt_record(custom_domain.domain)

        elif request.form.get("form-name") == "check-dkim":
            dkim_record = get_cname_record("dkim._domainkey." +
                                           custom_domain.domain)
            if dkim_record == dkim_cname:
                flash("DKIM is setup correctly.", "success")
                custom_domain.dkim_verified = True
                db.session.commit()

                return redirect(
                    url_for("dashboard.domain_detail_dns",
                            custom_domain_id=custom_domain.id))
            else:
                custom_domain.dkim_verified = False
                db.session.commit()
                flash("DKIM: the CNAME record is not correctly set", "warning")
                dkim_ok = False
                dkim_errors = [dkim_record or "[Empty]"]

        elif request.form.get("form-name") == "check-dmarc":
            txt_records = get_txt_record("_dmarc." + custom_domain.domain)
            if dmarc_record in txt_records:
                custom_domain.dmarc_verified = True
                db.session.commit()
                flash("DMARC is setup correctly", "success")
                return redirect(
                    url_for("dashboard.domain_detail_dns",
                            custom_domain_id=custom_domain.id))
            else:
                custom_domain.dmarc_verified = False
                db.session.commit()
                flash(
                    f"DMARC: The TXT record is not correctly set",
                    "warning",
                )
                dmarc_ok = False
                dmarc_errors = txt_records

    return render_template(
        "dashboard/domain_detail/dns.html",
        EMAIL_SERVERS_WITH_PRIORITY=EMAIL_SERVERS_WITH_PRIORITY,
        **locals(),
    )
예제 #7
0
def domain_detail_dns(custom_domain_id):
    custom_domain: CustomDomain = 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"))

    # generate a domain ownership txt token if needed
    if not custom_domain.ownership_verified and not custom_domain.ownership_txt_token:
        custom_domain.ownership_txt_token = random_string(30)
        Session.commit()

    spf_record = f"v=spf1 include:{EMAIL_DOMAIN} ~all"

    # hardcode the DKIM selector here
    dkim_cname = f"dkim._domainkey.{EMAIL_DOMAIN}"

    dmarc_record = "v=DMARC1; p=quarantine; pct=100; adkim=s; aspf=s"

    mx_ok = spf_ok = dkim_ok = dmarc_ok = ownership_ok = True
    mx_errors = spf_errors = dkim_errors = dmarc_errors = ownership_errors = []

    if request.method == "POST":
        if request.form.get("form-name") == "check-ownership":
            txt_records = get_txt_record(custom_domain.domain)

            if custom_domain.get_ownership_dns_txt_value() in txt_records:
                flash(
                    "Domain ownership is verified. Please proceed to the other records setup",
                    "success",
                )
                custom_domain.ownership_verified = True
                Session.commit()
                return redirect(
                    url_for(
                        "dashboard.domain_detail_dns",
                        custom_domain_id=custom_domain.id,
                        _anchor="dns-setup",
                    )
                )
            else:
                flash("We can't find the needed TXT record", "error")
                ownership_ok = False
                ownership_errors = txt_records

        elif request.form.get("form-name") == "check-mx":
            mx_domains = get_mx_domains(custom_domain.domain)

            if not is_mx_equivalent(mx_domains, EMAIL_SERVERS_WITH_PRIORITY):
                flash("The MX record is not correctly set", "warning")

                mx_ok = False
                # build mx_errors to show to user
                mx_errors = [
                    f"{priority} {domain}" for (priority, domain) in mx_domains
                ]
            else:
                flash(
                    "Your domain can start receiving emails. You can now use it to create alias",
                    "success",
                )
                custom_domain.verified = True
                Session.commit()
                return redirect(
                    url_for(
                        "dashboard.domain_detail_dns", custom_domain_id=custom_domain.id
                    )
                )
        elif request.form.get("form-name") == "check-spf":
            spf_domains = get_spf_domain(custom_domain.domain)
            if EMAIL_DOMAIN in spf_domains:
                custom_domain.spf_verified = True
                Session.commit()
                flash("SPF is setup correctly", "success")
                return redirect(
                    url_for(
                        "dashboard.domain_detail_dns", custom_domain_id=custom_domain.id
                    )
                )
            else:
                custom_domain.spf_verified = False
                Session.commit()
                flash(
                    f"SPF: {EMAIL_DOMAIN} is not included in your SPF record.",
                    "warning",
                )
                spf_ok = False
                spf_errors = get_txt_record(custom_domain.domain)

        elif request.form.get("form-name") == "check-dkim":
            dkim_record = get_cname_record("dkim._domainkey." + custom_domain.domain)
            if dkim_record == dkim_cname:
                flash("DKIM is setup correctly.", "success")
                custom_domain.dkim_verified = True
                Session.commit()

                return redirect(
                    url_for(
                        "dashboard.domain_detail_dns", custom_domain_id=custom_domain.id
                    )
                )
            else:
                custom_domain.dkim_verified = False
                Session.commit()
                flash("DKIM: the CNAME record is not correctly set", "warning")
                dkim_ok = False
                dkim_errors = [dkim_record or "[Empty]"]

        elif request.form.get("form-name") == "check-dmarc":
            txt_records = get_txt_record("_dmarc." + custom_domain.domain)
            if dmarc_record in txt_records:
                custom_domain.dmarc_verified = True
                Session.commit()
                flash("DMARC is setup correctly", "success")
                return redirect(
                    url_for(
                        "dashboard.domain_detail_dns", custom_domain_id=custom_domain.id
                    )
                )
            else:
                custom_domain.dmarc_verified = False
                Session.commit()
                flash(
                    "DMARC: The TXT record is not correctly set",
                    "warning",
                )
                dmarc_ok = False
                dmarc_errors = txt_records

    return render_template(
        "dashboard/domain_detail/dns.html",
        EMAIL_SERVERS_WITH_PRIORITY=EMAIL_SERVERS_WITH_PRIORITY,
        **locals(),
    )
예제 #8
0
def domain_detail_dns(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 sorted(mx_domains) != sorted(EMAIL_SERVERS_WITH_PRIORITY):
                mx_ok = False
                # build mx_errors to show to user
                mx_errors = [
                    f"{priority} {domain}" for (priority, domain) in mx_domains
                ]
            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_dns",
                            custom_domain_id=custom_domain.id))
        elif request.form.get("form-name") == "check-spf":
            spf_domains = get_spf_domain(custom_domain.domain)
            if EMAIL_DOMAIN in spf_domains:
                custom_domain.spf_verified = True
                db.session.commit()
                flash("The SPF is setup correctly", "success")
                return redirect(
                    url_for("dashboard.domain_detail_dns",
                            custom_domain_id=custom_domain.id))
            else:
                flash(f"{EMAIL_DOMAIN} is not included in your SPF record.",
                      "warning")
                spf_ok = False
                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_dns",
                            custom_domain_id=custom_domain.id))
            else:
                dkim_ok = False
                dkim_errors = get_txt_record(
                    f"dkim._domainkey.{custom_domain.domain}")

    spf_record = f"v=spf1 include:{EMAIL_DOMAIN} -all"

    dkim_record = f"v=DKIM1; k=rsa; p={DKIM_DNS_VALUE}"

    return render_template(
        "dashboard/domain_detail/dns.html",
        EMAIL_SERVERS_WITH_PRIORITY=EMAIL_SERVERS_WITH_PRIORITY,
        **locals(),
    )
예제 #9
0
def custom_domain():
    # only premium user can add custom domain
    if not current_user.is_premium():
        flash("Only premium user can add custom domains", "warning")
        return redirect(url_for("dashboard.index"))

    custom_domains = CustomDomain.query.filter_by(user_id=current_user.id).all()

    new_custom_domain_form = NewCustomDomainForm()

    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 new_custom_domain_form.validate():
                new_custom_domain = CustomDomain.create(
                    domain=new_custom_domain_form.domain.data, user_id=current_user.id
                )
                db.session.commit()

                flash(
                    f"New domain {new_custom_domain.domain} has been created successfully",
                    "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",
                    )
                    custom_domain.verified = True
                    db.session.commit()

    return render_template(
        "dashboard/custom_domain.html",
        custom_domains=custom_domains,
        new_custom_domain_form=new_custom_domain_form,
        EMAIL_SERVERS_WITH_PRIORITY=EMAIL_SERVERS_WITH_PRIORITY,
        errors=errors,
    )