Browse Source

[IMP] mail_tracking_mailgun: validation auto check

- Configurable partner email auto check.
pull/236/head
David 7 years ago
parent
commit
e20daeface
  1. 4
      mail_tracking_mailgun/README.rst
  2. 58
      mail_tracking_mailgun/models/mail_tracking_email.py
  3. 55
      mail_tracking_mailgun/models/res_partner.py
  4. 8
      mail_tracking_mailgun/tests/test_mailgun.py

4
mail_tracking_mailgun/README.rst

@ -40,6 +40,10 @@ parameters:
validity you must config this parameter with your account Public Validation validity you must config this parameter with your account Public Validation
Key. Key.
You can also config partner email autocheck with this system parameter:
- `mailgun.auto_check_partner_email`: Set it to True.
Usage Usage
===== =====

58
mail_tracking_mailgun/models/mail_tracking_email.py

@ -242,10 +242,10 @@ class MailTrackingEmail(models.Model):
if "items" not in content: if "items" not in content:
raise ValidationError(_("Event information not longer stored")) raise ValidationError(_("Event information not longer stored"))
for item in content["items"]: for item in content["items"]:
if not self.env['mail.tracking.event'].search(
# mailgun event hasn't been synced and recipient is the same as # mailgun event hasn't been synced and recipient is the same as
# in the evaluated tracking. We use email_split since tracking # in the evaluated tracking. We use email_split since tracking
# recipient could come in format: "example" <to@dest.com> # recipient could come in format: "example" <to@dest.com>
if not self.env['mail.tracking.event'].search(
[('mailgun_id', '=', item["id"])]) and ( [('mailgun_id', '=', item["id"])]) and (
item.get("recipient", "") == item.get("recipient", "") ==
email_split(tracking.recipient)[0]): email_split(tracking.recipient)[0]):
@ -254,59 +254,3 @@ class MailTrackingEmail(models.Model):
metadata = self._mailgun_metadata( metadata = self._mailgun_metadata(
mapped_event_type, item, {}) mapped_event_type, item, {})
tracking.event_create(mapped_event_type, metadata) tracking.event_create(mapped_event_type, metadata)
@api.multi
def check_email_list_validity(self, email_list):
"""
Checks email list validity with Mailgun's API
API documentation:
https://documentation.mailgun.com/en/latest/api-email-validation.html
"""
api_key, api_url, domain, validation_key = self.env[
'mail.tracking.email']._mailgun_values()
if not validation_key:
raise UserError(_('You need to configure mailgun.validation_key'
' in order to be able to check mails validity'))
result = {}
for email in email_list:
res = requests.get(
"%s/address/validate" % api_url,
auth=("api", validation_key), params={
"address": email,
"mailbox_verification": True,
})
if not res or res.status_code != 200:
result[email] = {'result': (_(
'Error %s trying to '
'check mail' % res.status_code or 'of connection'))}
continue
content = json.loads(res.content, res.apparent_encoding)
if 'mailbox_verification' not in content:
result[email] = {'result': (
_("Mailgun Error. Mailbox verification value wasn't"
" returned"))}
continue
# Not a valid address: API sets 'is_valid' as False
# and 'mailbox_verification' as None
if not content['is_valid']:
result[email] = {'result': (
_('%s is not a valid email address. Please check it '
'in order to avoid sending issues') % (email))}
continue
# If the mailbox is not valid API returns 'mailbox_verification'
# as a string with value 'false'
if content['mailbox_verification'] == 'false':
result[email] = {'result': (
_('%s failed the mailbox verification. Please check it '
'in order to avoid sending issues') % (email))}
continue
# If Mailgun can't complete the validation request the API returns
# 'mailbox_verification' as a string set to 'unknown'
if content['mailbox_verification'] == 'unknown':
result[email] = {'result': (
_("%s couldn't be verified. Either the request couln't be "
"completed or the mailbox provider doesn't support "
"email verification") % (email))}
continue
result[email] = {'result': _("The mailbox is correct")}
return result

55
mail_tracking_mailgun/models/res_partner.py

@ -45,43 +45,50 @@ class ResPartner(models.Model):
if not validation_key: if not validation_key:
raise UserError(_('You need to configure mailgun.validation_key' raise UserError(_('You need to configure mailgun.validation_key'
' in order to be able to check mails validity')) ' in order to be able to check mails validity'))
for partner in self:
for partner in self.filtered('email'):
res = requests.get( res = requests.get(
"%s/address/validate" % api_url, "%s/address/validate" % api_url,
auth=("api", validation_key), params={ auth=("api", validation_key), params={
"address": partner.email, "address": partner.email,
"mailbox_verification": True, "mailbox_verification": True,
}) })
if not res or res.status_code != 200:
if not res or res.status_code != 200 and not self.env.context.get(
'mailgun_auto_check'):
raise UserError(_( raise UserError(_(
'Error %s trying to ' 'Error %s trying to '
'check mail' % res.status_code or 'of connection')) 'check mail' % res.status_code or 'of connection'))
content = json.loads(res.content, res.apparent_encoding) content = json.loads(res.content, res.apparent_encoding)
if 'mailbox_verification' not in content: if 'mailbox_verification' not in content:
raise UserError(
_("Mailgun Error. Mailbox verification value wasn't"
" returned"))
if not self.env.context.get('mailgun_auto_check'):
raise UserError(
_("Mailgun Error. Mailbox verification value wasn't"
" returned"))
# Not a valid address: API sets 'is_valid' as False # Not a valid address: API sets 'is_valid' as False
# and 'mailbox_verification' as None # and 'mailbox_verification' as None
if not content['is_valid']: if not content['is_valid']:
partner.email_bounced = True partner.email_bounced = True
raise UserError(
_('%s is not a valid email address. Please check it '
'in order to avoid sending issues') % (partner.email))
body = _('%s is not a valid email address. Please check it'
' in order to avoid sending issues') % partner.email
if not self.env.context.get('mailgun_auto_check'):
raise UserError(body)
partner.message_post(body=body)
# If the mailbox is not valid API returns 'mailbox_verification' # If the mailbox is not valid API returns 'mailbox_verification'
# as a string with value 'false' # as a string with value 'false'
if content['mailbox_verification'] == 'false': if content['mailbox_verification'] == 'false':
partner.email_bounced = True partner.email_bounced = True
raise UserError(
_('%s failed the mailbox verification. Please check it '
'in order to avoid sending issues') % (partner.email))
body = _('%s failed the mailbox verification. Please check it'
' in order to avoid sending issues') % partner.email
if not self.env.context.get('mailgun_auto_check'):
raise UserError(body)
partner.message_post(body=body)
# If Mailgun can't complete the validation request the API returns # If Mailgun can't complete the validation request the API returns
# 'mailbox_verification' as a string set to 'unknown' # 'mailbox_verification' as a string set to 'unknown'
if content['mailbox_verification'] == 'unknown': if content['mailbox_verification'] == 'unknown':
raise UserError(
_("%s couldn't be verified. Either the request couln't be "
"completed or the mailbox provider doesn't support "
"email verification") % (partner.email))
if not self.env.context.get('mailgun_auto_check'):
raise UserError(
_("%s couldn't be verified. Either the request couln't"
" be completed or the mailbox provider doesn't "
"support email verification") % (partner.email))
@api.multi @api.multi
def check_email_bounced(self): def check_email_bounced(self):
@ -133,3 +140,21 @@ class ResPartner(models.Model):
auth=("api", api_key)) auth=("api", api_key))
if res.status_code in (200, 404) and partner.email_bounced: if res.status_code in (200, 404) and partner.email_bounced:
partner.email_bounced = False partner.email_bounced = False
def _autocheck_partner_email(self):
for partner in self:
partner.with_context(
mailgun_auto_check=True).check_email_validity()
@api.model
def create(self, vals):
if 'email' in vals and self.env['ir.config_parameter'].get_param(
'mailgun.auto_check_partner_email'):
self._autocheck_partner_email()
return super(ResPartner, self).create(vals)
def write(self, vals):
if 'email' in vals and self.env['ir.config_parameter'].get_param(
'mailgun.auto_check_partner_email'):
self._autocheck_partner_email()
return super(ResPartner, self).write(vals)

8
mail_tracking_mailgun/tests/test_mailgun.py

@ -43,6 +43,8 @@ class TestMailgun(TransactionCase):
'mail.catchall.domain', self.domain) 'mail.catchall.domain', self.domain)
self.env['ir.config_parameter'].set_param( self.env['ir.config_parameter'].set_param(
'mailgun.validation_key', self.api_key) 'mailgun.validation_key', self.api_key)
self.env['ir.config_parameter'].set_param(
'mailgun.auto_check_partner_email', '')
self.event = { self.event = {
'Message-Id': u'<xxx.xxx.xxx-openerp-xxx-res.partner@test_db>', 'Message-Id': u'<xxx.xxx.xxx-openerp-xxx-res.partner@test_db>',
'X-Mailgun-Sid': u'WyIwNjgxZSIsICJ0b0BleGFtcGxlLmNvbSIsICI3MG' 'X-Mailgun-Sid': u'WyIwNjgxZSIsICJ0b0BleGFtcGxlLmNvbSIsICI3MG'
@ -332,14 +334,16 @@ class TestMailgun(TransactionCase):
@mock.patch(_packagepath + '.models.res_partner.requests') @mock.patch(_packagepath + '.models.res_partner.requests')
def test_email_validity(self, mock_request): def test_email_validity(self, mock_request):
self.partner.email_bounced = False self.partner.email_bounced = False
self.partner.email = 'info@tecnativa.com'
mock_request.get.return_value.apparent_encoding = 'ascii' mock_request.get.return_value.apparent_encoding = 'ascii'
mock_request.get.return_value.status_code = 200 mock_request.get.return_value.status_code = 200
mock_request.get.return_value.content = json.dumps({ mock_request.get.return_value.content = json.dumps({
'is_valid': True, 'is_valid': True,
'mailbox_verification': 'true', 'mailbox_verification': 'true',
}, ensure_ascii=True) }, ensure_ascii=True)
self.partner.check_email_validity()
# Trigger email auto validation in partner
self.env['ir.config_parameter'].set_param(
'mailgun.auto_check_partner_email', 'True')
self.partner.email = 'info@tecnativa.com'
self.assertFalse(self.partner.email_bounced) self.assertFalse(self.partner.email_bounced)
self.partner.email = 'xoxoxoxo@tecnativa.com' self.partner.email = 'xoxoxoxo@tecnativa.com'
# Not a valid mailbox # Not a valid mailbox

Loading…
Cancel
Save