Merge pull request #923 from bearstech/improve_mx

improve mx search
This commit is contained in:
Antoine Nguyen
2016-09-29 21:28:44 +02:00
committed by GitHub
6 changed files with 69 additions and 28 deletions
+2 -2
View File
@@ -7,8 +7,8 @@ from . import models
@receiver(signals.post_save, sender=models.Domain)
def update_domain_mailboxes(sender, instance, **kwargs):
"""Update associated mailboxes."""
def update_domain_mxs_and_mailboxes(sender, instance, **kwargs):
"""Update associated MXs and mailboxes."""
if kwargs.get("created"):
return
instance.mailbox_set.filter(use_domain_quota=True).update(
@@ -57,6 +57,9 @@ class CheckMXRecords(BaseCommand):
"--skip-admin-emails", action="store_true",
default=False,
help="Skip domain's admins email notification.")
parser.add_argument(
"--domain", type=str, action="append", default=[],
help="Domain name or id to update.")
parser.add_argument(
"--timeout", type=int, default=3,
help="Timeout used for queries.")
@@ -80,28 +83,29 @@ class CheckMXRecords(BaseCommand):
models.MXRecord.objects.filter(domain=domain).delete()
try:
answers = dns.resolver.query(domain.name, "MX")
except (dns.resolver.NoAnswer, dns.resolver.NXDOMAIN):
except (dns.resolver.NoAnswer, dns.resolver.NXDOMAIN,
dns.resolver.NoNameservers):
raise StopIteration()
delta = timedelta(seconds=ttl)
for answer in answers:
address = None
try:
ipaddress.ip_address(str(answer.exchange))
except ValueError:
try:
address = socket.gethostbyname(str(answer.exchange))
except socket.gaierror:
pass
# work if .exchange is a name or IP
address = socket.gethostbyname(str(answer.exchange))
except socket.gaierror:
pass
else:
address = str(answer.exchange)
finally:
if address is not None:
try:
# we must have a valid IP
address = ipaddress.ip_address(u'{}'.format(address))
except ValueError:
pass
else:
record = models.MXRecord.objects.create(
domain=domain,
name=str(answer.exchange).strip("."),
address=address,
name=u'{}'.format(str(answer.exchange).strip(".")),
address=u'{}'.format(address),
updated=now + delta)
yield record
@@ -237,5 +241,19 @@ class CheckMXRecords(BaseCommand):
models.DNSBLResult.objects.exclude(
provider__in=self.providers).delete()
for domain in models.Domain.objects.filter(enabled=True):
if options['domain']:
domains = []
for domain in options['domain']:
if isinstance(domain, models.Domain):
domains.append(domain)
elif domain.isdigit():
domains.append(models.Domain.objects.get(domain))
else:
domains.append(models.Domain.objects.filter(name=domain))
else:
domains = models.Domain.objects.filter(enabled=True)
options.pop('domain')
for domain in domains:
self.check_domain(domain, **options)
+15 -2
View File
@@ -1,7 +1,10 @@
"""Models related to domains management."""
import datetime
from django.db import models
from django.db.models.manager import Manager
from django.utils import timezone
from django.utils.encoding import python_2_unicode_compatible, smart_text
from django.utils.functional import cached_property
from django.utils.translation import ugettext as _, ugettext_lazy
@@ -103,8 +106,18 @@ class Domain(AdminObject):
return self.domainalias_set
@property
def mx_records(self):
self.mxrecord_set
def just_created(self):
"""return true if the domain was created in the latest 24h"""
now = timezone.now()
delta = datetime.timedelta(days=1)
return self.creation + delta > now
def awaiting_checks(self):
"""return true if the domain has no valid MX records and was created
in the latest 24h"""
if (not self.mxrecord_set.has_valids()) and self.just_created:
return True
return False
@cached_property
def dnsbl_status_color(self):
@@ -24,11 +24,15 @@
{% if enable_mx_checks == "yes" or enable_dnsbl_checks == "yes" %}
<div class="row">
<span class="title">{% trans "DNS status" %}</span>
{% if enable_mx_checks == "yes" %}
<span class="label label-mini label-{% if not domain.mxrecord_set.has_valids %}danger{% else %}success{% endif %}"><a href="{% url 'admin:mx_domain_detail' domain.pk %}" data-toggle="ajaxmodal">MX</a></span>
{% endif %}
{% if enable_dnsbl_checks == "yes" %}
<span class="label label-{{ domain.dnsbl_status_color }}"><a href="{% url 'admin:dnsbl_domain_detail' domain.pk %}" data-toggle="ajaxmodal">DNSBL</a></span>
{% if domain.awaiting_checks %}
<span class="label label-mini label-info">{% trans "Awaiting checks" %}</span>
{% else %}
{% if enable_mx_checks == "yes" %}
<span class="label label-mini label-{% if not domain.mxrecord_set.has_valids %}danger{% else %}success{% endif %}"><a href="{% url 'admin:mx_domain_detail' domain.pk %}" data-toggle="ajaxmodal">MX</a></span>
{% endif %}
{% if enable_dnsbl_checks == "yes" %}
<span class="label label-mini label-{{ domain.dnsbl_status_color }}"><a href="{% url 'admin:dnsbl_domain_detail' domain.pk %}" data-toggle="ajaxmodal">DNSBL</a></span>
{% endif %}
{% endif %}
</div>
{% endif %}
@@ -8,11 +8,15 @@
{% if enable_mx_checks == "yes" or enable_dnsbl_checks == "yes" %}
<td name="dns">
<small>
{% if enable_mx_checks == "yes" %}
<span class="label label-mini label-{% if not domain.mxrecord_set.has_valids %}danger{% else %}success{% endif %}"><a href="{% url 'admin:mx_domain_detail' domain.pk %}" data-toggle="ajaxmodal">MX</a></span>
{% endif %}
{% if enable_dnsbl_checks == "yes" %}
<span class="label label-mini label-{{ domain.dnsbl_status_color }}"><a href="{% url 'admin:dnsbl_domain_detail' domain.pk %}" data-toggle="ajaxmodal">DNSBL</a></span>
{% if domain.awaiting_checks %}
<span class="label label-mini label-info">{% trans "Awaiting checks" %}</span>
{% else %}
{% if enable_mx_checks == "yes" %}
<span class="label label-mini label-{% if not domain.mxrecord_set.has_valids %}danger{% else %}success{% endif %}"><a href="{% url 'admin:mx_domain_detail' domain.pk %}" data-toggle="ajaxmodal">MX</a></span>
{% endif %}
{% if enable_dnsbl_checks == "yes" %}
<span class="label label-mini label-{{ domain.dnsbl_status_color }}"><a href="{% url 'admin:dnsbl_domain_detail' domain.pk %}" data-toggle="ajaxmodal">DNSBL</a></span>
{% endif %}
{% endif %}
</small>
</td>
+2
View File
@@ -21,6 +21,7 @@ class MXTestCase(ModoTestCase):
cls.domain = factories.DomainFactory(name="modoboa.org")
factories.DomainFactory(name="pouet.com") # should not exist
parameters.save_admin('VALID_MXS', '127.0.0.1', app='admin')
models.MXRecord.objects.all().delete()
def test_management_command(self):
"""Check that command works fine."""
@@ -53,6 +54,7 @@ class DNSBLTestCase(ModoTestCase):
super(DNSBLTestCase, cls).setUpTestData()
cls.domain = factories.DomainFactory(name="modoboa.org")
factories.DomainFactory(name="pouet.com") # should not exist
models.DNSBLResult.objects.all().delete()
@override_settings(DNSBL_PROVIDERS=["zen.spamhaus.org"])
def test_management_command(self):