Module: EmailAddress::Rewriter
- Included in:
- Address
- Defined in:
- lib/email_address/rewriter.rb
Constant Summary collapse
- SRS_FORMAT_REGEX =
/\ASRS0=(....)=(\w\w)=(.+?)=(.+?)@(.+)\z/
- PRVS_REGEX =
/\Aprvs=(\d)(\d{3})(\w{6})=(.+)\z/
Instance Method Summary collapse
-
#batv_prvs(options = {}) ⇒ Object
————————————————————————— Returns a BATV form email address with “Private Signature” (prvs).
- #parse_prvs(email, options = {}) ⇒ Object
- #parse_rewritten(e) ⇒ Object
- #parse_srs(email, options = {}, &block) ⇒ Object
- #prvs_day(days) ⇒ Object
- #prvs_sign(k, ddd, email, options = {}) ⇒ Object
-
#srs(sending_domain, options = {}, &block) ⇒ Object
————————————————————————— SRS (Sender Rewriting Scheme) allows an address to be forwarded from the original owner and encoded to be used with the domain name of the MTA (Mail Transport Agent).
- #srs?(email) ⇒ Boolean
- #srs_hash(email, options = {}, &block) ⇒ Object
-
#srs_tt(t = Time.now.utc) ⇒ Object
SRS Timeout Token Returns a 2-character code for the day.
-
#verp(recipient, split_char = "+") ⇒ Object
————————————————————————— VERP Embeds a recipient email address into the bounce address Bounce Address: [email protected] Recipient Email: [email protected] VERP : [email protected] To handle incoming verp, the “tag” is the recipient email address, remember to convert the last ‘=’ into a ‘@’ to reconstruct it.
Instance Method Details
#batv_prvs(options = {}) ⇒ Object
Returns a BATV form email address with “Private Signature” (prvs). Options: key: 0-9 key digit to use
key_0..key_9: secret key used to sign/verify
prvs_days: number of days before address "expires"
BATV - Bounce Address Tag Validation PRVS - Simple Private Signature Ex: [email protected]
* K: Digit for Key rotation
* DDD: Expiry date, since 1970, low 3 digits
* SSSSSS: sha1( KDDD + orig-mailfrom + key)[0,6]
See: tools.ietf.org/html/draft-levine-smtp-batv-01
86 87 88 89 90 91 92 |
# File 'lib/email_address/rewriter.rb', line 86 def batv_prvs( = {}) k = [:prvs_key_id] || "0" prvs_days = [:prvs_days] || @config[:prvs_days] || 30 ddd = prvs_day(prvs_days) ssssss = prvs_sign(k, ddd, to_s, ) ["prvs=", k, ddd, ssssss, "=", to_s].join("") end |
#parse_prvs(email, options = {}) ⇒ Object
96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 |
# File 'lib/email_address/rewriter.rb', line 96 def parse_prvs(email, = {}) if email.match(PRVS_REGEX) @rewrite_scheme = :prvs k, ddd, ssssss, email = [$1, $2, $3, $4] unless ssssss == prvs_sign(k, ddd, email, ) @rewrite_error = "Invalid BATV Address: Signature unverified" end exp = ddd.to_i roll = 1000 - exp # rolling 1000 day window today = prvs_day(0) # I'm sure this is wrong if exp > today && exp < roll @rewrite_error = "Invalid SRS Email Address: Address expired" elsif exp < today && (today - exp) > 0 @rewrite_error = "Invalid SRS Email Address: Address expired" end [local, domain].join("@") else email end end |
#parse_rewritten(e) ⇒ Object
8 9 10 11 12 13 |
# File 'lib/email_address/rewriter.rb', line 8 def parse_rewritten(e) @rewrite_scheme = nil @rewrite_error = nil parse_srs(e) # e = parse_batv(e) end |
#parse_srs(email, options = {}, &block) ⇒ Object
37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 |
# File 'lib/email_address/rewriter.rb', line 37 def parse_srs(email, = {}, &block) if email&.match(SRS_FORMAT_REGEX) @rewrite_scheme = :srs hhh, tt, domain, local, sending_domain = [$1, $2, $3, $4, $5] # hhh = tt = sending_domain if false && hhh # Hide warnings for now :-) a = [tt, domain, local].join("=") + "@" + sending_domain unless srs_hash(a, , &block) === hhh @rewrite_error = "Invalid SRS Email Address: Possibly altered" end unless tt == srs_tt @rewrite_error = "Invalid SRS Email Address: Too old" end [local, domain].join("@") else email end end |
#prvs_day(days) ⇒ Object
119 120 121 |
# File 'lib/email_address/rewriter.rb', line 119 def prvs_day(days) ((Time.now.to_i + (days * 24 * 60 * 60)) / (24 * 60 * 60)).to_s[-3, 3] end |
#prvs_sign(k, ddd, email, options = {}) ⇒ Object
123 124 125 126 127 |
# File 'lib/email_address/rewriter.rb', line 123 def prvs_sign(k, ddd, email, = {}) str = [ddd, ssssss, "=", to_s].join("") key = ["key_#{k}".to_i] || @config["key_#{k}".to_i] || str.reverse Digest::SHA1.hexdigest([k, ddd, email, key].join(""))[0, 6] end |
#srs(sending_domain, options = {}, &block) ⇒ Object
SRS (Sender Rewriting Scheme) allows an address to be forwarded from the original owner and encoded to be used with the domain name of the MTA (Mail Transport Agent). It encodes the original address within the local part of the sending email address and respects VERP. If example.com needs to forward a message from “[email protected]”, the SMTP envelope sender is used at this address. These methods respect DMARC and prevent spoofing email send using a different domain. Format: [email protected]
25 26 27 28 29 30 31 |
# File 'lib/email_address/rewriter.rb', line 25 def srs(sending_domain, = {}, &block) tt = srs_tt a = [tt, hostname, local.to_s].join("=") + "@" + sending_domain hhh = srs_hash(a, , &block) ["SRS0", hhh, a].join("=") end |
#srs?(email) ⇒ Boolean
33 34 35 |
# File 'lib/email_address/rewriter.rb', line 33 def srs?(email) email.match(SRS_FORMAT_REGEX) ? true : false end |
#srs_hash(email, options = {}, &block) ⇒ Object
63 64 65 66 67 68 69 70 |
# File 'lib/email_address/rewriter.rb', line 63 def srs_hash(email, = {}, &block) key = [:key] || @config[:key] || email.reverse if block block.call(email)[0, 4] else Base64.encode64(Digest::SHA1.digest(email + key))[0, 4] end end |
#srs_tt(t = Time.now.utc) ⇒ Object
SRS Timeout Token Returns a 2-character code for the day. After a few days the code will roll. TT has a one-day resolution in order to make the address invalid after a few days. The cycle period is 3.5 years. Used to control late bounces and harvesting.
59 60 61 |
# File 'lib/email_address/rewriter.rb', line 59 def srs_tt(t = Time.now.utc) Base64.encode64((t.to_i / (60 * 60 * 24) % 210).to_s)[0, 2] end |
#verp(recipient, split_char = "+") ⇒ Object
VERP Embeds a recipient email address into the bounce address
Bounce Address: [email protected]
Recipient Email: [email protected]
VERP : [email protected]
To handle incoming verp, the “tag” is the recipient email address, remember to convert the last ‘=’ into a ‘@’ to reconstruct it.
137 138 139 140 141 |
# File 'lib/email_address/rewriter.rb', line 137 def verp(recipient, split_char = "+") local.to_s + split_char + recipient.tr("@", "=") + "@" + hostname end |