is_email 0.1.1
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/CHANGELOG.md +13 -0
- data/CONTRIBUTING.md +55 -0
- data/LICENSE.md +21 -0
- data/README.md +61 -0
- data/is_email.gemspec +31 -0
- data/lib/is_email/diagnosis/base.rb +76 -0
- data/lib/is_email/diagnosis/cfws.rb +27 -0
- data/lib/is_email/diagnosis/deprecated.rb +42 -0
- data/lib/is_email/diagnosis/invalid.rb +90 -0
- data/lib/is_email/diagnosis/rfc5321.rb +36 -0
- data/lib/is_email/diagnosis/rfc5322.rb +60 -0
- data/lib/is_email/diagnosis/valid.rb +28 -0
- data/lib/is_email/diagnosis.rb +25 -0
- data/lib/is_email/reference.rb +158 -0
- data/lib/is_email/validators/base.rb +23 -0
- data/lib/is_email/validators/parser.rb +1056 -0
- data/lib/is_email/validators.rb +8 -0
- data/lib/is_email/version.rb +5 -0
- data/lib/is_email.rb +64 -0
- metadata +72 -0
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA256:
|
3
|
+
metadata.gz: 57746b49f1766781b186aa9ab5c3fd6be76c21df3e5b9555dc76e12460602bf6
|
4
|
+
data.tar.gz: 0a7deddacae4136f0f854a5f7045852ee9c38ab0f3cd32ce416ed62bc8bd83c0
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: 032d3f9a9cccad36d5506b93f6aabc8c1cc316869a4c079b9f272b2f666bf6fd8bd516ad95386d7c7b03fd09f6d2b7476f69ab15f58a660df86fba6a5d3fb02f
|
7
|
+
data.tar.gz: b153e65860a93daf83bcd468ce0f33c0cf3d7407f1136f491edddea17d34fbd55bee8e1629a0bbb8a1c68b624ca2813b026dfac140493d46c3502adaa22a6aa0
|
data/CHANGELOG.md
ADDED
@@ -0,0 +1,13 @@
|
|
1
|
+
# Changelog
|
2
|
+
|
3
|
+
All notable changes to this project will be documented in this file.
|
4
|
+
|
5
|
+
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/), and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
|
6
|
+
|
7
|
+
## [0.1.1](https://github.com/michaelherold/is_email/tree/0.1.1) - 2023-06-18
|
8
|
+
|
9
|
+
- Add support for parsing email addresses according to the relevant RFCs and outputting either a boolean or a diagnosis. This is and will continue to be the default behavior of `IsEmail.email?`.
|
10
|
+
|
11
|
+
## 0.1.0
|
12
|
+
|
13
|
+
- An initial push that wasn't vetted thoroughly enough and missed updating the changelog with the release date. Otherwise, this was identical to 0.1.1.
|
data/CONTRIBUTING.md
ADDED
@@ -0,0 +1,55 @@
|
|
1
|
+
# Contributing
|
2
|
+
|
3
|
+
In the spirit of [free software](http://www.fsf.org/licensing/essays/free-sw.html), we encourage **everyone** to help improve this project. Here are some ways _you_ can contribute:
|
4
|
+
|
5
|
+
* Use alpha, beta, and pre-release versions.
|
6
|
+
* Report bugs.
|
7
|
+
* Suggest new features.
|
8
|
+
* Write or edit documentation.
|
9
|
+
* Write specifications.
|
10
|
+
* Write code (**no patch is too small**: fix typos, add comments, clean up inconsistent whitespace).
|
11
|
+
* Refactor code.
|
12
|
+
* Fix [issues].
|
13
|
+
* Review patches.
|
14
|
+
|
15
|
+
[issues]: https://github.com/michaelherold/is_email/issues
|
16
|
+
|
17
|
+
## Submitting an Issue
|
18
|
+
|
19
|
+
We use the [GitHub issue tracker][issues] to track bugs and features. Before submitting a bug report or feature request, check to make sure no one has already submitted it.
|
20
|
+
|
21
|
+
When submitting a bug report, please include a `<details>` block that includes a stack trace and any details that may be necessary to reproduce the bug, including your gem version, Ruby version, and operating system. This looks like the following:
|
22
|
+
|
23
|
+
```markdown
|
24
|
+
<details>
|
25
|
+
<summary>A description of the details block</summary>
|
26
|
+
|
27
|
+
All of the content that you want in here, perhaps with code fences. Note that
|
28
|
+
if you only have a code fence in here, you _must_ separate it from the <summary>
|
29
|
+
tag and the closing </details> or it won't render correctly.
|
30
|
+
|
31
|
+
Notice the empty line here ↓
|
32
|
+
|
33
|
+
</details>
|
34
|
+
```
|
35
|
+
|
36
|
+
Ideally, a bug report should include a pull request with failing specs.
|
37
|
+
|
38
|
+
## Submitting a Pull Request
|
39
|
+
|
40
|
+
1. Fork the repository.
|
41
|
+
2. Create a topic branch.
|
42
|
+
3. Add specs for your unimplemented feature or bug fix.
|
43
|
+
4. Run `bundle exec rake test`. If your specs pass, return to step 3.
|
44
|
+
5. Implement your feature or bug fix.
|
45
|
+
6. Run `bundle exec rake`. If your specs or any of the linters fail, return to step 5.
|
46
|
+
7. Open `coverage/index.html`. If your changes are not fully covered by your tests, return to step 3.
|
47
|
+
8. Add documentation for your feature or bug fix.
|
48
|
+
9. Commit and push your changes.
|
49
|
+
10. Submit a pull request.
|
50
|
+
|
51
|
+
## Tools to Help You Succeed
|
52
|
+
|
53
|
+
After checking out the repository, run `bin/setup` to install dependencies. Then, run `bundle exec rake test` to run the tests. You can also run `bin/console` for an interactive prompt that will allow you to experiment.
|
54
|
+
|
55
|
+
Before committing code, run `bundle exec rake` to check that the code conforms to the style guidelines of the project, that all of the tests are green (if you're writing a feature; if you're only submitting a failing test, then it does not have to pass!), and that you sufficiently documented the changes.
|
data/LICENSE.md
ADDED
@@ -0,0 +1,21 @@
|
|
1
|
+
# The MIT License (MIT)
|
2
|
+
|
3
|
+
Copyright © 2023 Michael Herold
|
4
|
+
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
7
|
+
in the Software without restriction, including without limitation the rights
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
10
|
+
furnished to do so, subject to the following conditions:
|
11
|
+
|
12
|
+
The above copyright notice and this permission notice shall be included in
|
13
|
+
all copies or substantial portions of the Software.
|
14
|
+
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
21
|
+
THE SOFTWARE.
|
data/README.md
ADDED
@@ -0,0 +1,61 @@
|
|
1
|
+
# IsEmail
|
2
|
+
|
3
|
+
IsEmail is a no-nonsense approach for checking whether that user-supplied email address could be real. Sick of not being able to use [email address tagging](http://en.wikipedia.org/wiki/Email_address#Address_tags) to sort through your [Bacn](https://en.wiktionary.org/wiki/bacn)? We can fix that.
|
4
|
+
|
5
|
+
Regular expressions are cheap to write, but often require maintenance when new top-level domains come out or don't conform to email addressing features that come back into vogue. IsEmail allows you to validate an email address — and even check the domain, if you wish — with one simple call, making your code more readable and faster to write. When you want to know why an email address doesn't validate, we even provide you with a diagnosis.
|
6
|
+
|
7
|
+
## Installation
|
8
|
+
|
9
|
+
Install the gem and add to the application's Gemfile by executing:
|
10
|
+
|
11
|
+
$ bundle add is_email
|
12
|
+
|
13
|
+
If you are not using Bundler to manage dependencies, install the gem by executing:
|
14
|
+
|
15
|
+
$ gem install is_email
|
16
|
+
|
17
|
+
## Usage
|
18
|
+
|
19
|
+
For the simplest usage, import and use the `IsEmail.email?` module method:
|
20
|
+
|
21
|
+
```ruby
|
22
|
+
address = "test@example.com"
|
23
|
+
bool_result = IsEmail.email?(address)
|
24
|
+
detailed_result = IsEmail.email?(address, diagnose: true)
|
25
|
+
```
|
26
|
+
|
27
|
+
## Contributing
|
28
|
+
|
29
|
+
So you're interested in contributing to IsEmail? Check out our [contributing guidelines](CONTRIBUTING.md) for more information on how to do that.
|
30
|
+
|
31
|
+
## Supported Ruby Versions
|
32
|
+
|
33
|
+
This library aims to support and is [tested against](https://github.com/michaelherold/is_email/actions) the following Ruby versions:
|
34
|
+
|
35
|
+
* Ruby 3.0
|
36
|
+
* Ruby 3.1
|
37
|
+
* Ruby 3.2
|
38
|
+
|
39
|
+
If something doesn't work on one of these versions, it's a bug.
|
40
|
+
|
41
|
+
This library may inadvertently work (or seem to work) on other Ruby versions, however we will only provide support for the versions listed above.
|
42
|
+
|
43
|
+
If you would like this library to support another Ruby version or implementation, you may volunteer to be a maintainer. Being a maintainer entails making sure all tests run and pass on that implementation. When something breaks on your implementation, you will be responsible for providing patches in a timely fashion. If critical issues for a particular implementation exist at the time of a major release, we may drop support for that Ruby version.
|
44
|
+
|
45
|
+
## Versioning
|
46
|
+
|
47
|
+
This library aims to adhere to [Semantic Versioning 2.0.0](http://semver.org/spec/v2.0.0.html). Report violations of this scheme should as bugs. Specifically, if a minor or patch version breaks backward compatibility, that version should be immediately yanked and/or a new version should be immediately released that restores compatibility. Only new major versions will introduce breaking changes to the public API. As a result of this policy, you can (and should) specify a dependency on this gem using the [pessimistic version constraint](http://guides.rubygems.org/patterns/#pessimistic-version-constraint) with two digits of precision. For example:
|
48
|
+
|
49
|
+
spec.add_dependency "is_email", "~> 0.1"
|
50
|
+
|
51
|
+
## License
|
52
|
+
|
53
|
+
The gem is available as open source under the terms of the [MIT License](https://opensource.org/licenses/MIT).
|
54
|
+
|
55
|
+
## Code of Conduct
|
56
|
+
|
57
|
+
We expect everyone interacting in the IsEmail project's codebases, issue trackers, chat rooms and mailing lists to follow the [code of conduct](https://github.com/michaelherold/is_email/blob/main/CODE_OF_CONDUCT.md).
|
58
|
+
|
59
|
+
## Acknowledgments
|
60
|
+
|
61
|
+
I based the base `Validators::Parser` off [Dominic Sayers](https://github.com/dominicsayers)'s [is_email script](https://github.com/dominicsayers/isemail). I wanted the functionality in Python, so I ported it from the original PHP. I later ported it to Ruby since it's handy to have there too.
|
data/is_email.gemspec
ADDED
@@ -0,0 +1,31 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require_relative "lib/is_email/version"
|
4
|
+
|
5
|
+
Gem::Specification.new do |spec|
|
6
|
+
spec.name = "is_email"
|
7
|
+
spec.version = IsEmail::VERSION
|
8
|
+
spec.authors = ["Michael Herold"]
|
9
|
+
spec.email = ["opensource@michaeljherold.com"]
|
10
|
+
|
11
|
+
spec.summary = "is_email is a no-nonsense approach for checking whether that user-supplied email address could be real. Sick of not being able to use email address tagging to sort through your Bacn? We can fix that."
|
12
|
+
spec.description = spec.summary
|
13
|
+
spec.homepage = "https://github.com/michaelherold/is_email"
|
14
|
+
spec.license = "MIT"
|
15
|
+
|
16
|
+
spec.required_ruby_version = ">= 3.0.0"
|
17
|
+
|
18
|
+
spec.files = %w[CHANGELOG.md CONTRIBUTING.md LICENSE.md README.md]
|
19
|
+
spec.files += %w[is_email.gemspec]
|
20
|
+
spec.files += Dir["lib/**/*.rb"]
|
21
|
+
spec.require_paths = ["lib"]
|
22
|
+
|
23
|
+
spec.metadata = {
|
24
|
+
"bug_tracker_uri" => "https://github.com/michaelherold/is_email/issues",
|
25
|
+
"changelog_uri" => "https://github.com/michaelherold/is_email/blob/main/CHANGELOG.md",
|
26
|
+
"documentation_uri" => "https://rubydoc.info/gems/is_email/#{IsEmail::VERSION}",
|
27
|
+
"homepage_uri" => "https://github.com/michaelherold/is_email",
|
28
|
+
"rubygems_mfa_required" => "true",
|
29
|
+
"source_code_uri" => "https://github.com/michaelherold/is_email"
|
30
|
+
}
|
31
|
+
end
|
@@ -0,0 +1,76 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module IsEmail
|
4
|
+
module Diagnosis
|
5
|
+
# An abstract superclass for all diagnoses
|
6
|
+
#
|
7
|
+
# @api private
|
8
|
+
class Base
|
9
|
+
include Comparable
|
10
|
+
|
11
|
+
DESCRIPTION = ""
|
12
|
+
ERROR_CODES = {}.freeze
|
13
|
+
MESSAGES = {}.freeze
|
14
|
+
REFERENCES = {}.freeze
|
15
|
+
|
16
|
+
# @param type [String]
|
17
|
+
# @return [void]
|
18
|
+
def initialize(type)
|
19
|
+
@code = self.class::ERROR_CODES.fetch(type)
|
20
|
+
@message = self.class::MESSAGES.fetch(type, "")
|
21
|
+
@references = self.class::REFERENCES.fetch(type) { [] }.map { |ref| Reference.new(ref) }
|
22
|
+
@type = type.to_s
|
23
|
+
end
|
24
|
+
|
25
|
+
# @return [Integer]
|
26
|
+
attr_reader :code
|
27
|
+
|
28
|
+
# @return [String]
|
29
|
+
attr_reader :message
|
30
|
+
|
31
|
+
# @return [Array<Reference>]
|
32
|
+
attr_reader :references
|
33
|
+
|
34
|
+
# @return [String]
|
35
|
+
attr_reader :type
|
36
|
+
|
37
|
+
# Part of the [value object semantics][1] to make diagnoses equalable
|
38
|
+
#
|
39
|
+
# [1]: https://thoughtbot.com/blog/value-object-semantics-in-ruby
|
40
|
+
#
|
41
|
+
# @param other [Object]
|
42
|
+
# @return [Boolean]
|
43
|
+
def ==(other)
|
44
|
+
other.instance_of?(self.class) && (self <=> other).zero?
|
45
|
+
end
|
46
|
+
alias_method :eql?, :==
|
47
|
+
|
48
|
+
# Allows sorting with Numerics and other diagnoses
|
49
|
+
#
|
50
|
+
# @param other [Object]
|
51
|
+
# @return [-1, 0, 1, nil]
|
52
|
+
def <=>(other)
|
53
|
+
case other
|
54
|
+
when Base
|
55
|
+
code <=> other.code
|
56
|
+
when Numeric
|
57
|
+
code <=> other
|
58
|
+
end
|
59
|
+
end
|
60
|
+
|
61
|
+
# Part of the [value object semantics][1] to make diagnoses equalable
|
62
|
+
#
|
63
|
+
# [1]: https://thoughtbot.com/blog/value-object-semantics-in-ruby
|
64
|
+
#
|
65
|
+
# @return [Integer]
|
66
|
+
def hash
|
67
|
+
[self.class, type].hash
|
68
|
+
end
|
69
|
+
|
70
|
+
# @return [String]
|
71
|
+
def inspect
|
72
|
+
"#<#{self.class.name}: #{type}>"
|
73
|
+
end
|
74
|
+
end
|
75
|
+
end
|
76
|
+
end
|
@@ -0,0 +1,27 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module IsEmail
|
4
|
+
module Diagnosis
|
5
|
+
# Indicates an address has a Comment or Folding White Space
|
6
|
+
#
|
7
|
+
# @api private
|
8
|
+
class CFWS < Base
|
9
|
+
DESCRIPTION = "Address is valid within the message but cannot be used unmodified for the envelope."
|
10
|
+
|
11
|
+
ERROR_CODES = {
|
12
|
+
"COMMENT" => 17,
|
13
|
+
"FWS" => 18
|
14
|
+
}.freeze
|
15
|
+
|
16
|
+
MESSAGES = {
|
17
|
+
"COMMENT" => "Address contains messages",
|
18
|
+
"FWS" => "Address contains Folding White Space"
|
19
|
+
}.freeze
|
20
|
+
|
21
|
+
REFERENCES = {
|
22
|
+
"COMMENT" => ["dot-atom"],
|
23
|
+
"FWS" => ["local-part"]
|
24
|
+
}.freeze
|
25
|
+
end
|
26
|
+
end
|
27
|
+
end
|
@@ -0,0 +1,42 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module IsEmail
|
4
|
+
module Diagnosis
|
5
|
+
# Indicates an address has deprecated elements but may still be usable
|
6
|
+
#
|
7
|
+
# @api private
|
8
|
+
class Deprecated < Base
|
9
|
+
DESCRIPTION = "Address contains deprecated elements but may still be valid in restricted contexts."
|
10
|
+
|
11
|
+
ERROR_CODES = {
|
12
|
+
"LOCALPART" => 33,
|
13
|
+
"FWS" => 34,
|
14
|
+
"QTEXT" => 35,
|
15
|
+
"QP" => 36,
|
16
|
+
"COMMENT" => 37,
|
17
|
+
"CTEXT" => 38,
|
18
|
+
"CFWS_NEAR_AT" => 49
|
19
|
+
}.freeze
|
20
|
+
|
21
|
+
MESSAGES = {
|
22
|
+
"LOCALPART" => "Address contains a local part in deprecated form.",
|
23
|
+
"FWS" => "Address contains Folding White Space in deprecated form.",
|
24
|
+
"QTEXT" => "Address contains a quoted string in deprecated form.",
|
25
|
+
"QP" => "Address contains a quoted pair in deprecated form.",
|
26
|
+
"COMMENT" => "Address contains a comment in deprecated form.",
|
27
|
+
"CTEXT" => "Address contains a comment with a deprecated character.",
|
28
|
+
"CFWS_NEAR_AT" => "Address contains a comment or Folding White Space around the @ sign."
|
29
|
+
}.freeze
|
30
|
+
|
31
|
+
REFERENCES = {
|
32
|
+
"LOCALPART" => ["obs-local-part"],
|
33
|
+
"FWS" => ["obs-local-part", "obs-domain"],
|
34
|
+
"QTEXT" => ["obs-qtext"],
|
35
|
+
"QP" => ["obs-qp"],
|
36
|
+
"COMMENT" => ["obs-local-part", "obs-domain"],
|
37
|
+
"CTEXT" => ["obs-ctext"],
|
38
|
+
"CFWS_NEAR_AT" => ["CFWS-near-at", "SHOULD-NOT"]
|
39
|
+
}.freeze
|
40
|
+
end
|
41
|
+
end
|
42
|
+
end
|
@@ -0,0 +1,90 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module IsEmail
|
4
|
+
module Diagnosis
|
5
|
+
# Indicates an address is invalid for any purpose
|
6
|
+
#
|
7
|
+
# @api private
|
8
|
+
class Invalid < Base
|
9
|
+
DESCRIPTION = "Address is invalid for any purpose"
|
10
|
+
|
11
|
+
ERROR_CODES = {
|
12
|
+
"EXPECTING_DTEXT" => 129,
|
13
|
+
"NOLOCALPART" => 130,
|
14
|
+
"NODOMAIN" => 131,
|
15
|
+
"CONSECUTIVEDOTS" => 132,
|
16
|
+
"ATEXT_AFTER_CFWS" => 133,
|
17
|
+
"ATEXT_AFTER_QS" => 134,
|
18
|
+
"ATEXT_AFTER_DOMLIT" => 135,
|
19
|
+
"EXPECTING_QPAIR" => 136,
|
20
|
+
"EXPECTING_ATEXT" => 137,
|
21
|
+
"EXPECTING_QTEXT" => 138,
|
22
|
+
"EXPECTING_CTEXT" => 139,
|
23
|
+
"BACKSLASHEND" => 140,
|
24
|
+
"DOT_START" => 141,
|
25
|
+
"DOT_END" => 142,
|
26
|
+
"DOMAINHYPHENSTART" => 143,
|
27
|
+
"DOMAINHYPHENEND" => 144,
|
28
|
+
"UNCLOSEDQUOTEDSTR" => 145,
|
29
|
+
"UNCLOSEDCOMMENT" => 146,
|
30
|
+
"UNCLOSEDDOMLIT" => 147,
|
31
|
+
"FWS_CRLF_X2" => 148,
|
32
|
+
"FWS_CRLF_END" => 149,
|
33
|
+
"CR_NO_LF" => 150,
|
34
|
+
"BAD_PARSE" => 151
|
35
|
+
}
|
36
|
+
|
37
|
+
MESSAGES = {
|
38
|
+
"EXPECTING_DTEXT" => "Address contains a character that is not allowed in a domain literal.",
|
39
|
+
"NOLOCALPART" => "Address has no local part.",
|
40
|
+
"NODOMAIN" => "Address has no domain part.",
|
41
|
+
"CONSECUTIVEDOTS" => "Address contains consecutive dots.",
|
42
|
+
"ATEXT_AFTER_CFWS" => "Address contains text after a comment or Folding White Space.",
|
43
|
+
"ATEXT_AFTER_QS" => "Address contains text after a quoted string.",
|
44
|
+
"ATEXT_AFTER_DOMLIT" => "Address contains extra characters after the domain literal.",
|
45
|
+
"EXPECTING_QPAIR" => "Address contains a character that is not allowed in a quoted pair.",
|
46
|
+
"EXPECTING_ATEXT" => "Address contains a character that is not allowed.",
|
47
|
+
"EXPECTING_QTEXT" => "Address contains a character that is not allowed in a quoted string.",
|
48
|
+
"EXPECTING_CTEXT" => "Address contains a character that is not allowed in a comment.",
|
49
|
+
"BACKSLASHEND" => "Address ends in a backslash.",
|
50
|
+
"DOT_START" => "Address has a local part or domain that begins with a dot.",
|
51
|
+
"DOT_END" => "Address has a local part or domain that ends with a dot.",
|
52
|
+
"DOMAINHYPHENSTART" => "Address has a local part or domain that begins with a hyphen.",
|
53
|
+
"DOMAINHYPHENEND" => "Address has a local part or domain that ends with a hyphen.",
|
54
|
+
"UNCLOSEDQUOTEDSTR" => "Address contains an unclosed quoted string.",
|
55
|
+
"UNCLOSEDCOMMENT" => "Address contains an unclosed comment.",
|
56
|
+
"UNCLOSEDDOMLIT" => "Address contains a domain literal that is missing its closing bracket.",
|
57
|
+
"FWS_CRLF_X2" => "Address contains a Folding White Space that has consecutive CRLF sequences.",
|
58
|
+
"FWS_CRLF_END" => "Address contains a Folding White Space that ends with a CRLF sequence.",
|
59
|
+
"CR_NO_LF" => "Address contains a carriage return that is not followed by a line return.",
|
60
|
+
"BAD_PARSE" => "Address is malformed."
|
61
|
+
}
|
62
|
+
|
63
|
+
REFERENCES = {
|
64
|
+
"EXPECTING_DTEXT" => ["dtext"],
|
65
|
+
"NOLOCALPART" => ["local-part"],
|
66
|
+
"NODOMAIN" => ["addr-spec", "mailbox"],
|
67
|
+
"CONSECUTIVEDOTS" => ["local-part", "domain-RFC5322", "domain-RFC5321"],
|
68
|
+
"ATEXT_AFTER_CFWS" => ["local-part", "domain-RFC5322"],
|
69
|
+
"ATEXT_AFTER_QS" => ["local-part"],
|
70
|
+
"ATEXT_AFTER_DOMLIT" => ["domain-RFC5322"],
|
71
|
+
"EXPECTING_QPAIR" => ["quoted-pair"],
|
72
|
+
"EXPECTING_ATEXT" => ["atext"],
|
73
|
+
"EXPECTING_QTEXT" => ["qtext"],
|
74
|
+
"EXPECTING_CTEXT" => ["ctext"],
|
75
|
+
"BACKSLASHEND" => ["domain-RFC5322", "domain-RFC5321", "quoted-pair"],
|
76
|
+
"DOT_START" => ["local-part", "domain-RFC5322", "domain-RFC5321"],
|
77
|
+
"DOT_END" => ["local-part", "domain-RFC5322", "domain-RFC5321"],
|
78
|
+
"DOMAINHYPHENSTART" => ["sub-domain"],
|
79
|
+
"DOMAINHYPHENEND" => ["sub-domain"],
|
80
|
+
"UNCLOSEDQUOTEDSTR" => ["quoted-string"],
|
81
|
+
"UNCLOSEDCOMMENT" => ["CFWS"],
|
82
|
+
"UNCLOSEDDOMLIT" => ["domain-literal"],
|
83
|
+
"FWS_CRLF_X2" => ["CFWS"],
|
84
|
+
"FWS_CRLF_END" => ["CFWS"],
|
85
|
+
"CR_NO_LF" => ["CFWS", "CRLF"],
|
86
|
+
"BAD_PARSE" => []
|
87
|
+
}
|
88
|
+
end
|
89
|
+
end
|
90
|
+
end
|
@@ -0,0 +1,36 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module IsEmail
|
4
|
+
module Diagnosis
|
5
|
+
# Indicates an address is valid for SMTP but is unusual
|
6
|
+
#
|
7
|
+
# @api private
|
8
|
+
class RFC5321 < Base
|
9
|
+
DESCRIPTION = "Address is valid for SMTP but has unusual elements."
|
10
|
+
|
11
|
+
ERROR_CODES = {
|
12
|
+
"TLD" => 9,
|
13
|
+
"TLDNUMERIC" => 10,
|
14
|
+
"QUOTEDSTRING" => 11,
|
15
|
+
"ADDRESSLITERAL" => 12,
|
16
|
+
"IPV6DEPRECATED" => 13
|
17
|
+
}
|
18
|
+
|
19
|
+
MESSAGES = {
|
20
|
+
"TLD" => "Address is valid but at a Top Level Domain.",
|
21
|
+
"TLDNUMERIC" => "Address is valid but the Top Level Domain begins with a number.",
|
22
|
+
"QUOTEDSTRING" => "Address is valid but contains a quoted string.",
|
23
|
+
"ADDRESSLITERAL" => "Address is valid but at a literal address, not a domain.",
|
24
|
+
"IPV6DEPRECATED" => "Address is valid but contains a :: that only elides one zero group."
|
25
|
+
}
|
26
|
+
|
27
|
+
REFERENCES = {
|
28
|
+
"TLD" => ["TLD"],
|
29
|
+
"TLDNUMERIC" => ["TLD-format"],
|
30
|
+
"QUOTEDSTRING" => ["quoted-string"],
|
31
|
+
"ADDRESSLITERAL" => ["address-literal", "address-literal-IPv4"],
|
32
|
+
"IPV6DEPRECATED" => ["address-literal-IPv6"]
|
33
|
+
}
|
34
|
+
end
|
35
|
+
end
|
36
|
+
end
|
@@ -0,0 +1,60 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module IsEmail
|
4
|
+
module Diagnosis
|
5
|
+
# Indicates an address is only loosely valid by RFC5322
|
6
|
+
#
|
7
|
+
# @api private
|
8
|
+
class RFC5322 < Base
|
9
|
+
DESCRIPTION = "Address is only valid according to the broad definition of RFC5322. It is otherwise invalid."
|
10
|
+
|
11
|
+
ERROR_CODES = {
|
12
|
+
"DOMAIN" => 65,
|
13
|
+
"TOOLONG" => 66,
|
14
|
+
"LOCAL_TOOLONG" => 67,
|
15
|
+
"DOMAIN_TOOLONG" => 68,
|
16
|
+
"LABEL_TOOLONG" => 69,
|
17
|
+
"DOMAINLITERAL" => 70,
|
18
|
+
"DOMLIT_OBSDTEXT" => 71,
|
19
|
+
"IPV6_GRPCOUNT" => 72,
|
20
|
+
"IPV6_2X2XCOLON" => 73,
|
21
|
+
"IPV6_BADCHAR" => 74,
|
22
|
+
"IPV6_MAXGRPS" => 75,
|
23
|
+
"IPV6_COLONSTRT" => 76,
|
24
|
+
"IPV6_COLONEND" => 77
|
25
|
+
}
|
26
|
+
|
27
|
+
MESSAGES = {
|
28
|
+
"DOMAIN" => "Address is RFC5322 compliant but contains domain characters that are not allowed by DNS.",
|
29
|
+
"TOOLONG" => "Address is too long.",
|
30
|
+
"LOCAL_TOOLONG" => "Address contains a local part that is too long.",
|
31
|
+
"DOMAIN_TOOLONG" => "Address contains a domain that is too long.",
|
32
|
+
"LABEL_TOOLONG" => "Address contains a domain part with an element that is too long.",
|
33
|
+
"DOMAINLITERAL" => "Address contains a domain literal that is not a valid RFC5321 address literal.",
|
34
|
+
"DOMLIT_OBSDTEXT" => "Address contains a domain literal that is not a valid RFC5321 address literal and contains obsolete characters.",
|
35
|
+
"IPV6_GRPCOUNT" => "Address contains an IPv6 literal address with the wrong number of groups.",
|
36
|
+
"IPV6_2X2XCOLON" => "Address contains an IPv6 literal address with too many :: sequences.",
|
37
|
+
"IPV6_BADCHAR" => "Address contains an IPv6 literal address with an illegal group of characters.",
|
38
|
+
"IPV6_MAXGRPS" => "Address contains an IPv6 literal address with too many groups.",
|
39
|
+
"IPV6_COLONSTRT" => "Address contains an IPv6 literal address that starts with a single colon.",
|
40
|
+
"IPV6_COLONEND" => "Address contains an IPv6 literal address that ends with a single colon."
|
41
|
+
}
|
42
|
+
|
43
|
+
REFERENCES = {
|
44
|
+
"DOMAIN" => ["domain-RFC5322"],
|
45
|
+
"TOOLONG" => ["mailbox-maximum"],
|
46
|
+
"LOCAL_TOOLONG" => ["local-part-maximum"],
|
47
|
+
"DOMAIN_TOOLONG" => ["domain-maximum"],
|
48
|
+
"LABEL_TOOLONG" => ["label"],
|
49
|
+
"DOMAINLITERAL" => ["domain-literal"],
|
50
|
+
"DOMLIT_OBSDTEXT" => ["obs-dtext"],
|
51
|
+
"IPV6_GRPCOUNT" => ["address-literal-IPv6"],
|
52
|
+
"IPV6_2X2XCOLON" => ["address-literal-IPv6"],
|
53
|
+
"IPV6_BADCHAR" => ["address-literal-IPv6"],
|
54
|
+
"IPV6_MAXGRPS" => ["address-literal-IPv6"],
|
55
|
+
"IPV6_COLONSTRT" => ["address-literal-IPv6"],
|
56
|
+
"IPV6_COLONEND" => ["address-literal-IPv6"]
|
57
|
+
}
|
58
|
+
end
|
59
|
+
end
|
60
|
+
end
|
@@ -0,0 +1,28 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module IsEmail
|
4
|
+
module Diagnosis
|
5
|
+
# Indicates an address is valid
|
6
|
+
#
|
7
|
+
# @api private
|
8
|
+
class Valid < Base
|
9
|
+
DESCRIPTION = "Address is valid."
|
10
|
+
|
11
|
+
ERROR_CODES = {"VALID" => 1}.freeze
|
12
|
+
|
13
|
+
MESSAGES = {
|
14
|
+
"VALID" =>
|
15
|
+
"Address is valid. Please note that this does not mean " \
|
16
|
+
"the address actually exists, nor even that the domain " \
|
17
|
+
"actually exists. This address could be issued by the " \
|
18
|
+
"domain owner without breaking the rules of any RFCs."
|
19
|
+
}.freeze
|
20
|
+
|
21
|
+
# @param type [String]
|
22
|
+
# @return [void]
|
23
|
+
def initialize(type = "VALID")
|
24
|
+
super
|
25
|
+
end
|
26
|
+
end
|
27
|
+
end
|
28
|
+
end
|
@@ -0,0 +1,25 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module IsEmail
|
4
|
+
# Contains all types of diagnoses for address invalidity
|
5
|
+
module Diagnosis
|
6
|
+
require_relative "diagnosis/base"
|
7
|
+
require_relative "diagnosis/cfws"
|
8
|
+
require_relative "diagnosis/deprecated"
|
9
|
+
require_relative "diagnosis/invalid"
|
10
|
+
require_relative "diagnosis/rfc5321"
|
11
|
+
require_relative "diagnosis/rfc5322"
|
12
|
+
require_relative "diagnosis/valid"
|
13
|
+
|
14
|
+
CATEGORIES = {
|
15
|
+
"VALID" => 1,
|
16
|
+
"DNSWARN" => 7,
|
17
|
+
"RFC5321" => 15,
|
18
|
+
"THRESHOLD" => 16,
|
19
|
+
"CFWS" => 31,
|
20
|
+
"DEPREC" => 63,
|
21
|
+
"RFC5322" => 127,
|
22
|
+
"ERR" => 255
|
23
|
+
}.freeze
|
24
|
+
end
|
25
|
+
end
|