mailshield 1.6 → 1.7

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 951a883218a7b24ca485ad6e34755a420a754931ebb5590438e5ae3715ba385a
4
- data.tar.gz: 74522e2cc5992814083ebb6235a849ff0429f9482bcdec848911526511a386cf
3
+ metadata.gz: 18604539d1e37e6bb2be57844fc3f4655db6aad98fd6f8d8509264b55ab9cf8a
4
+ data.tar.gz: 55fc76651d319aa7f5c7289270dcfb13d7fbacfa0c1ca9ca5d8fdf19c268f14d
5
5
  SHA512:
6
- metadata.gz: fbc024e630f232ff8bb84fff735076c0f8b9c698a12874dc622b4fda4885b4daf7574a830a8acd109d2b3e57fc9265b877516556de71b936b9e3c22f32d01a7e
7
- data.tar.gz: 87b6a352c1e0307983ffae13f9675e97712d7c786ce39a84a4e09c0a9c6d3764a1c756fdd18ca4aabdb8fd08c11667d5dcdf8e8beaf0fd08322dc657bd13ff77
6
+ metadata.gz: 3b2ab77713d4d23a5836419b01df0c804bcc66291f5efb259dc437e9584fc7ee6ef933401701332e4105877e56da3beea02b51c7b1f06ccc49f958cac6ba9cc2
7
+ data.tar.gz: 53771549f5c3c334906acbeea35df4277581431a8fbe83636ace180ab25e7ae4bb0e80ebcbab87a28cd45c813665a29b731017966ad160ab4ec89ee18c83b287
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Mailshield
4
- VERSION = '1.6'
4
+ VERSION = '1.7'
5
5
  end
data/lib/mailshield.rb CHANGED
@@ -8,8 +8,10 @@ require 'csv'
8
8
  require 'net/smtp'
9
9
 
10
10
  module MailShield
11
+ # Regex pattern for validating email formats
11
12
  EMAIL_REGEX = /\A[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,}\z/.freeze
12
13
 
14
+ # Custom error classes for various validation failures
13
15
  class ValidationError < StandardError; end
14
16
  class InvalidFormatError < ValidationError; end
15
17
  class DomainNotFoundError < ValidationError; end
@@ -17,57 +19,94 @@ module MailShield
17
19
  class DMARCError < ValidationError; end
18
20
  class SMTPError < ValidationError; end
19
21
  class TemporaryDomainError < ValidationError; end
22
+
20
23
  class << self
21
24
  attr_accessor :dns_cache, :smtp_cache, :whitelist, :blacklist
22
25
 
26
+ # Configuration method for initializing and yielding settings
23
27
  def configure
24
- @whitelist ||= []
25
- @blacklist ||= []
26
- yield self
28
+ initialize_lists
29
+ yield self if block_given?
27
30
  end
28
31
 
32
+ # Validate the structure and existence of the provided email
29
33
  def validate_email(email)
30
34
  reset_caches
31
-
32
35
  domain = extract_domain(email)
33
36
 
34
- return { valid: false, reason: 'Email domain is blacklisted.' } if blacklist.include?(domain)
37
+ return { valid: false, reason: 'Email domain is blacklisted.' } if blacklist && blacklist.include?(domain)
35
38
 
36
- if !whitelist.empty? && !whitelist.include?(domain)
39
+ if whitelist && !whitelist.empty? && !whitelist.include?(domain)
37
40
  return { valid: false, reason: 'Email domain is not whitelisted.' }
38
41
  end
39
42
 
40
- begin
41
- validate_known_disposal_domain?(domain)
42
- validate_format!(email)
43
- validate_domain!(domain)
44
- validate_spf!(domain)
45
- validate_dmarc!(domain)
46
- validate_smtp!(email)
47
- rescue ValidationError => e
48
- return { valid: false, reason: e.message }
49
- end
50
-
51
- { valid: true }
43
+ # Perform comprehensive validation checks
44
+ perform_validations(email, domain)
52
45
  end
53
46
 
54
- # Added Support for verifying email existance in real world
55
47
  def email_exists?(email)
56
48
  smtp_verify_email(email)
57
49
  end
58
50
 
59
- # Added Support for Email Format Validation
60
51
  def valid_format?(email)
61
52
  valid_email_format?(email)
62
53
  end
63
54
 
64
55
  private
65
56
 
57
+ # Initialize lists for whitelisting and blacklisting
58
+ def initialize_lists
59
+ @whitelist ||= []
60
+ @blacklist ||= []
61
+ end
62
+
66
63
  def reset_caches
67
64
  @dns_cache = {}
68
65
  @smtp_cache = {}
69
66
  end
70
67
 
68
+ def blacklisted?(domain)
69
+ blacklist.include?(domain)
70
+ end
71
+
72
+ def handle_blacklist(domain)
73
+ {
74
+ valid: false,
75
+ reason: 'Email domain is blacklisted.'
76
+ }
77
+ end
78
+
79
+ def whitelisted?(domain)
80
+ !whitelist.empty? && whitelist.include?(domain)
81
+ end
82
+
83
+ def handle_whitelist(domain)
84
+ {
85
+ valid: false,
86
+ reason: 'Email domain is not whitelisted.'
87
+ }
88
+ end
89
+
90
+ # Perform all necessary validations for the given email
91
+ def perform_validations(email, domain)
92
+ begin
93
+ validate_known_disposal_domain?(domain) # Custom method to check for disposable domains
94
+ validate_format!(email)
95
+ validate_domain!(domain)
96
+ validate_spf!(domain)
97
+ validate_dmarc!(domain)
98
+ validate_smtp!(email)
99
+ rescue ValidationError => e
100
+ return handle_validation_error(e)
101
+ end
102
+
103
+ { valid: true }
104
+ end
105
+
106
+ def handle_validation_error(error)
107
+ { valid: false, reason: error.message }
108
+ end
109
+
71
110
  def validate_format!(email)
72
111
  raise InvalidFormatError, 'The email address format is invalid.' unless valid_email_format?(email)
73
112
  end
@@ -96,6 +135,7 @@ module MailShield
96
135
  EMAIL_REGEX.match?(email)
97
136
  end
98
137
 
138
+ # Fetch MX records for the given domain
99
139
  def fetch_mx_records(domain)
100
140
  Resolv::DNS.open do |dns|
101
141
  dns.getresources(domain, Resolv::DNS::Resource::IN::MX).map(&:exchange).map(&:to_s)
@@ -104,16 +144,19 @@ module MailShield
104
144
  []
105
145
  end
106
146
 
147
+ # Check if SPF records are available for the domain
107
148
  def spf_record?(domain)
108
149
  spf_records = fetch_txt_records(domain)
109
150
  spf_records.any? { |record| record.include?('v=spf1') }
110
151
  end
111
152
 
153
+ # Check if DMARC records are available for the domain
112
154
  def dmarc_record?(domain)
113
155
  dmarc_records = fetch_txt_records("_dmarc.#{domain}")
114
156
  dmarc_records.any? { |record| record.include?('v=DMARC1') }
115
157
  end
116
158
 
159
+ # Fetch TXT records for the domain
117
160
  def fetch_txt_records(domain)
118
161
  Resolv::DNS.open do |dns|
119
162
  records = dns.getresources(domain, Resolv::DNS::Resource::IN::TXT)
@@ -123,6 +166,7 @@ module MailShield
123
166
  []
124
167
  end
125
168
 
169
+ # Verify the email address using SMTP
126
170
  def smtp_verify_email(email)
127
171
  domain = extract_domain(email)
128
172
  smtp_server = get_smtp_server(domain)
@@ -134,13 +178,18 @@ module MailShield
134
178
  smtp.helo('localhost')
135
179
  smtp.mailfrom('test@example.com')
136
180
  response = smtp.rcptto(email)
137
- response.status == '250' || response.status == '250 OK'
181
+ smtp_response_status(response)
138
182
  end
139
183
  rescue Net::SMTPFatalError, Net::SMTPServerBusy, Net::SMTPSyntaxError, Errno::ECONNREFUSED
140
184
  false
141
185
  end
142
186
  end
143
187
 
188
+ def smtp_response_status(response)
189
+ response.status == '250' || response.status == '250 OK'
190
+ end
191
+
192
+ # Retrieve the SMTP server for the specified domain
144
193
  def get_smtp_server(domain)
145
194
  mx_records = fetch_mx_records(domain)
146
195
  mx_records.first
@@ -150,6 +199,7 @@ end
150
199
 
151
200
  module ActiveModel
152
201
  module Validations
202
+ # Validator for secure email verification
153
203
  class SecureEmailValidator < ::MailShield::SecureEmailValidator
154
204
  def initialize(options = {})
155
205
  super
metadata CHANGED
@@ -1,15 +1,29 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: mailshield
3
3
  version: !ruby/object:Gem::Version
4
- version: '1.6'
4
+ version: '1.7'
5
5
  platform: ruby
6
6
  authors:
7
7
  - jana
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2024-09-16 00:00:00.000000000 Z
11
+ date: 2024-10-05 00:00:00.000000000 Z
12
12
  dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: activemodel
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - ">="
18
+ - !ruby/object:Gem::Version
19
+ version: '0'
20
+ type: :runtime
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - ">="
25
+ - !ruby/object:Gem::Version
26
+ version: '0'
13
27
  - !ruby/object:Gem::Dependency
14
28
  name: net-smtp
15
29
  requirement: !ruby/object:Gem::Requirement