Email address validation, what the point?
Increasing delivery rates
Improving your email deliverability by removing all invalid email addresses from your list.
Maintains a high sender reputation
Malibox providers take a lot of metrics to check your sender reputation, one of them is mailing to unknown users.
Increasing conversion rate
More emails that arrive to inboxes means higher opens and clicks, and better performance overall.
Email Validation Methods
Regex validation
MX validation
SMTP validation
Regex Validation
Checking the email address via regex pattern
Regex Validation
TYPICAL_EMAIL = /(?=\A.{6,255}\z)(#{USER})@(#{DOMAIN})/
- should be one character or more
- may contain any word character, case insensitive
- may contain dots, hyphens, but not as first character
USER = /\A([a-z0-9]+[\w|\-|\.|\+]*/i
DOMAIN = /[a-z0-9]+([\-\.]{1}[a-z0-9]+)*\.[a-z]{2,63}/i
- should start from letter or number
- may contain dots, hyphens
- TLD should contain only letters and should be between 2 and 63 characters
- case insensitive
Not follow RFC 5322!
MX Validation
Checking the availability of the email address domain using DNS MX records
MX Validation
Domain MX lookup
MX records
resolver
CNAME records
resolver
A record
resolver
validation fails
false
false
false
true
true
true
validation
successful
MX Validation - step 1
MX records
resolver
$ dig example.com MX
example.com. IN MX 0 mail.example.com.
mail.example.com. IN A 127.0.0.1
mail.example.com. IN A 127.0.0.2
$ dig example.com MX
example.com. IN MX 0 .
Domain name
Transform each
MX record to
host address(es)
true
true
false
validation fails
false
CNAME records
resolver
[127.0.0.1, 127.0.0.2]
validation successful
MX Validation - step 2
CNAME records
resolver
$ dig mail.example.com CNAME
mail.example.com. 1423 IN CNAME mail.somedomain.net.
mail.somedomain.net. 6888 IN CNAME mail.nextdomain.com.
mail.nextdomain.com. 347 IN A 127.0.0.1
true
true
false
false
A record
resolver
MX records
resolver
Last CNAME host from each CNAME record
[127.0.0.1, 127.0.0.2]
validation
successful
MX Validation - step 3
A record
resolver
Do A records
exist?
$ dig mail.example.com A
mail.example.com. 347 IN A 127.0.0.1
mail.example.com. 355 IN A 127.0.0.2
true
false
[127.0.0.1]
validation fails
validation successful
SMTP Validation
Checking real existence of email account on a mail server
SMTP Validation
Each mail
server
validation
fails
false
false
true
true
validation
successful
Is the 25-port
opened?
Run
SMTP-session
false
Next
mail-server exists?
true
SMTP Validation - session
validation fails
true
true
validation successful
HELO/EHLO
false
MAILFROM
RCPTTO
Open session
$ nc server.example.com 25
220 server.example.com
$ HELO yourdomain.com
250 server.example.com
$ MAIL FROM: <email@yourdomain.com>
250 2.1.0 <email@yourdomain.com> ok
$ RCPT TO: <target_email@domain.com>
250 2.1.5 <target_email@domain.com> recipient ok
true
false
false
false
$ RCPT TO: <target_email@domain.com>
550 5.7.1 No such user!
should be a real
host address should has a ptr
record (rDNS) to HELO host
$ dig -x 127.0.1.1 # your host WAN IP
127.0.0.1.in-addr.arpa. 7194 IN PTR yourdomain.com.
Truemail
Configurable framework agnostic plain Ruby email validator/verifier.
Truemail
- Configurable validator
- Zero runtime dependencies
-
Has simple SMTP debugger
Why?
Truemail - configuration
Truemail.configure do |config|
config.verifier_email = 'verifier@example.com'
config.verifier_domain = 'somedomain.com'
config.email_pattern = /regex_pattern/
config.connection_timeout = 1
config.connection_attempts = 1
config.response_timeout = 1
config.validation_type_for = { 'somedomain.com' => :mx, 'otherdomain.org' => :regex }
config.smtp_safe_check = true
config.smtp_error_body_pattern = /regex_pattern/
end
Truemail - host audit
Truemail.host_audit
# Everything is good
=> #<Truemail::Auditor:0x00005580df358828
@result=
#<struct Truemail::Auditor::Result
warnings={}>>
# Has PTR warning
=> #<Truemail::Auditor:0x00005580df358828
@result=
#<struct Truemail::Auditor::Result
warnings=
{:ptr=>"ptr record does not reference to current verifier domain"}>>
Truemail gem allows performing an audit of the host in which runs. Only PTR record audit performs for today.
It will help to check:
- PTR existence
- PTR reference
- Reverse trace
Truemail - Regex validation
Truemail.validate('email@example.com', with: :regex)
=> #<Truemail::Validator:0x000055590cc9bdb8
@result=
#<struct Truemail::Validator::Result
success=true, email="email@example.com",
domain=nil,
mail_servers=[],
errors={},
smtp_debug=nil>,
@validation_type=:regex>
By default this validation not performs strictly following RFC 5322 standard, so you can override Truemail default regex pattern if you want.
Truemail - MX validation
Truemail.validate('email@example.com', with: :mx)
=> #<Truemail::Validator:0x000055590c9c1c50
@result=
#<struct Truemail::Validator::Result
success=true,
email="email@example.com",
domain="example.com",
mail_servers=["127.0.1.1", "127.0.1.2"],
errors={},
smtp_debug=nil>,
@validation_type=:mx>
Truemail MX validator not performs strict compliance of the RFC 5321 standard for best validation outcome. Iteration will be processed for this case too:
Regex
validation
MX
validation
MX 0 unresolvable.example.com.
MX 10 healthy1.example.com.
MX 20 healthy2.example.com.
Truemail - SMTP validation
Regex
validation
MX
validation
SMTP
validation
If total count of MX servers is equal to one, Truemail::Smtp validator will use value from Configuration.connection_attempts.
Also you don't need pass with-parameter to use this validation.
Truemail.validate('email@example.com')
# the same, no need to do it!
Truemail.validate('email@example.com', with: :smtp)
Truemail - SMTP validation
Truemail.validate('email@example.com')
# Successful SMTP validation
=> #<Truemail::Validator:0x000055590c4dc118
@result=
#<struct Truemail::Validator::Result
success=true,
email="email@example.com",
domain="example.com",
mail_servers=["127.0.1.1", "127.0.1.2"],
errors={},
smtp_debug=nil>,
@validation_type=:smtp>
With default settings, smtp_safe_check = false
Truemail - SMTP validation
# SMTP validation failed
=> #<Truemail::Validator:0x0000000002d5cee0
@result=
#<struct Truemail::Validator::Result
success=false,
email="email@example.com",
domain="example.com",
mail_servers=["127.0.1.1", "127.0.1.2"],
errors={:smtp=>"smtp error"},
smtp_debug=
[#<Truemail::Validate::Smtp::Request:0x0000000002d49b10
@configuration=#<Truemail::Configuration:0x0000000002d49930>,
@email="email@example.com",
@host="127.0.1.1",
@attempts=nil,
@response=
#<struct Truemail::Validate::Smtp::Response
port_opened=true,
connection=true,
helo=
#<Net::SMTP::Response:0x0000000002d5aca8
@status="250",
@string="250 127.0.1.1 Hello example.com\n">,
mailfrom=
#<Net::SMTP::Response:0x0000000002d5a618
@status="250",
@string="250 OK\n">,
rcptto=false,
errors={:rcptto=>"550 User not found\n"}>>]>,
@validation_type=:smtp>
With default settings,
smtp_safe_check = false
Truemail - SMTP validation
Truemail.validate('email@example.com')
# Successful SMTP validation
=> #<Truemail::Validator:0x0000000002ca2c70
@result=
#<struct Truemail::Validator::Result
success=true,
email="email@example.com",
domain="example.com",
mail_servers=["127.0.1.1", "127.0.1.2"],
errors={},
smtp_debug=
[#<Truemail::Validate::Smtp::Request:0x0000000002c95d40
@configuration=#<Truemail::Configuration:0x0000000002c95b38>
@email="email@example.com",
@host="127.0.1.1",
@attempts=nil,
@response=
#<struct Truemail::Validate::Smtp::Response
port_opened=true,
connection=false,
helo=
#<Net::SMTP::Response:0x0000000002c934c8
@status="250",
@string="250 127.0.1.1\n">,
mailfrom=false,
rcptto=nil,
errors={:mailfrom=>"554 5.7.1 Client host blocked\n", :connection=>"server dropped connection after response"}>>,]>,
@validation_type=:smtp>
With smtp_safe_check = true
It will be helpful if SMTP server does not return an exact answer that the email does not exist.
Truemail - SMTP validation
# SMTP validation failed
=> #<Truemail::Validator:0x0000000002d5cee0
@result=
#<struct Truemail::Validator::Result
success=false,
email="email@example.com",
domain="example.com",
mail_servers=["127.0.1.1", "127.0.1.2"],
errors={:smtp=>"smtp error"},
smtp_debug=
[#<Truemail::Validate::Smtp::Request:0x0000000002d49b10
@configuration=
#<Truemail::Configuration:0x0000000002d49930
@connection_timeout=2,
@email_pattern=/regex_pattern/,
@response_timeout=2,
@connection_attempts=2,
@smtp_safe_check=true,
@validation_type_by_domain={},
@verifier_domain="example.com",
@verifier_email="verifier@example.com">,
@email="email@example.com",
@host="127.0.1.1",
@attempts=nil,
@response=
#<struct Truemail::Validate::Smtp::Response
port_opened=true,
connection=true,
helo=
#<Net::SMTP::Response:0x0000000002d5aca8
@status="250",
@string="250 127.0.1.1 Hello example.com\n">,
mailfrom=#<Net::SMTP::Response:0x0000000002d5a618 @status="250", @string="250 OK\n">,
rcptto=false,
errors={:rcptto=>"550 User not found\n"}>>]>,
@validation_type=:smtp>
With smtp_safe_check = true
Truemail.configure do |c|
c.smtp_error_body_pattern = /regex/
end
Configurable option:
# Default regex SMTP error body pattern
/(?=.*550)(?=.*(user|account|customer|mailbox)).*/i
Truemail
Bug reports and pull requests are welcome on GitHub:
The End
Email validation
By Vladislav Trotsenko
Email validation
Email validation methods, Ruby implementation.
- 3,585