diff --git a/hobo/emails/validators.py b/hobo/emails/validators.py index d6b4bd0..8cb0669 100644 --- a/hobo/emails/validators.py +++ b/hobo/emails/validators.py @@ -23,14 +23,14 @@ from django.utils.translation import ugettext_lazy as _ def validate_email_address(value): + if not settings.HOBO_VALIDATE_EMAIL_WITH_SMTP: + return email_domain = value.split('@')[-1] try: - mx_server = dns.resolver.query(email_domain, 'MX')[0].exchange.to_text() - except dns.resolver.NXDOMAIN as e: + mx_server = sorted(dns.resolver.query(email_domain, 'MX'), key=lambda rdata: rdata.preference)[0].exchange.to_text() + except dns.exception.DNSException as e: raise ValidationError(_('Error: %s') % str(e)) - except dns.resolver.NoAnswer as e: - raise ValidationError(_('Error: %s') % str(e)) - smtp = smtplib.SMTP(timeout=30) + smtp = smtplib.SMTP(timeout=10) try: smtp.connect(mx_server) except socket.error as e: @@ -41,11 +41,9 @@ def validate_email_address(value): raise ValidationError(_('Error while connecting to %(server)s: %(msg)s') % {'server': mx_server, 'msg': msg}) smtp.mail('') status, msg = smtp.rcpt(value) - if status == 250: - smtp.quit() - return smtp.quit() - raise ValidationError(_('Email address not found on %s') % mx_server) + if status // 100 == 5: + raise ValidationError(_('Email address not found on %s') % mx_server) def validate_email_spf(value, strict=False): diff --git a/hobo/settings.py b/hobo/settings.py index 2118ec9..62749aa 100644 --- a/hobo/settings.py +++ b/hobo/settings.py @@ -26,6 +26,7 @@ DEBUG = True ALLOWED_HOSTS = [] +HOBO_VALIDATE_EMAIL_WITH_SMTP = True ALLOWED_SPF_RECORDS = [] # Application definition diff --git a/tests/test_emails.py b/tests/test_emails.py index c713d8d..e9b0e5f 100644 --- a/tests/test_emails.py +++ b/tests/test_emails.py @@ -22,6 +22,9 @@ def dns_resolver(monkeypatch): mx.exchange = mock.create_autospec(name.Name) mx.exchange.to_text = mock.MagicMock() mx.exchange.to_text.return_value = 'localhost:10025' + mx.preference = mock.create_autospec(name.Name) + mx.preference.to_text = mock.MagicMock() + mx.preference.to_text.return_value = 10 return [mx] if kind == 'TXT': txt = mock.create_autospec(TXT) @@ -86,6 +89,11 @@ def test_validate_email_address_socket_error(dns_resolver, monkeypatch): assert 'Error while connecting' in str(e.value) +def test_validate_email_address_bypass(settings): + settings.HOBO_VALIDATE_EMAIL_WITH_SMTP = False + assert validate_email_address('foo') == None + + def test_invalid_address(client, admin_user): client.post('/login/', {'username': 'admin', 'password': 'password'}) response = client.post('/emails/', {'default_from_email': 'foobar'})