Class: SanitizeEmail::OverriddenAddresses

Inherits:
Object
  • Object
show all
Defined in:
lib/sanitize_email/overridden_addresses.rb

Overview

Tools for overriding addresses

Defined Under Namespace

Classes: MissingRecipients, MissingTo, UnknownOverride

Constant Summary collapse

REPLACE_AT =
[/@/, " at "].freeze
REPLACE_ALLIGATOR =
[/[<>]/, "~"].freeze

Instance Attribute Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(message, **args) ⇒ OverriddenAddresses

Returns a new instance of OverriddenAddresses.



36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
# File 'lib/sanitize_email/overridden_addresses.rb', line 36

def initialize(message, **args)
  # Not using extract_options! because non-rails compatibility is a goal
  args = SanitizeEmail::Config.to_init.merge(args)
  @sanitized_to = args[:sanitized_to]
  @sanitized_cc = args[:sanitized_cc]
  @sanitized_bcc = args[:sanitized_bcc]
  @good_list = args[:good_list] || []
  @bad_list = args[:bad_list] || []
  # Mail will do the username parsing for us.
  @tempmail = Mail.new

  tempmail.to = to_override(message.to)
  tempmail.cc = cc_override(message.cc)
  tempmail.bcc = bcc_override(message.bcc)

  # remove addresses from :cc / :bcc that are also in :to
  remove_duplicates

  @overridden_to = tempmail[:to].decoded
  @overridden_cc = tempmail[:cc].decoded
  @overridden_bcc = tempmail[:bcc].decoded

  actual_personalizations = message["personalizations"]
  if actual_personalizations.nil?
    raise MissingRecipients, "No recipients left post-sanitization" if (tempmail.to + tempmail.cc + tempmail.bcc).empty?
  elsif actual_personalizations.respond_to?(:unparsed_value)
    @overridden_personalizations = personalizations_override(actual_personalizations)
  else
    # TODO: Remove check when dropping Rails 3.x
    #       undefined method `unparsed_value' for #<Mail::OptionalField>
    raise MissingRecipients, "Mail version is too old to use personalizations"
  end
end

Instance Attribute Details

#bad_listObject

Returns the value of attribute bad_list.



25
26
27
# File 'lib/sanitize_email/overridden_addresses.rb', line 25

def bad_list
  @bad_list
end

#good_listObject

Returns the value of attribute good_list.



25
26
27
# File 'lib/sanitize_email/overridden_addresses.rb', line 25

def good_list
  @good_list
end

#overridden_bccObject

Returns the value of attribute overridden_bcc.



25
26
27
# File 'lib/sanitize_email/overridden_addresses.rb', line 25

def overridden_bcc
  @overridden_bcc
end

#overridden_ccObject

Returns the value of attribute overridden_cc.



25
26
27
# File 'lib/sanitize_email/overridden_addresses.rb', line 25

def overridden_cc
  @overridden_cc
end

#overridden_personalizationsObject

Returns the value of attribute overridden_personalizations.



25
26
27
# File 'lib/sanitize_email/overridden_addresses.rb', line 25

def overridden_personalizations
  @overridden_personalizations
end

#overridden_toObject

Returns the value of attribute overridden_to.



25
26
27
# File 'lib/sanitize_email/overridden_addresses.rb', line 25

def overridden_to
  @overridden_to
end

#sanitized_bccObject

Returns the value of attribute sanitized_bcc.



25
26
27
# File 'lib/sanitize_email/overridden_addresses.rb', line 25

def sanitized_bcc
  @sanitized_bcc
end

#sanitized_ccObject

Returns the value of attribute sanitized_cc.



25
26
27
# File 'lib/sanitize_email/overridden_addresses.rb', line 25

def sanitized_cc
  @sanitized_cc
end

#sanitized_toObject

Returns the value of attribute sanitized_to.



25
26
27
# File 'lib/sanitize_email/overridden_addresses.rb', line 25

def sanitized_to
  @sanitized_to
end

#tempmailObject

Returns the value of attribute tempmail.



25
26
27
# File 'lib/sanitize_email/overridden_addresses.rb', line 25

def tempmail
  @tempmail
end

Instance Method Details

#address_list_filter(list_type, address) ⇒ Object



143
144
145
146
147
148
149
150
151
152
153
154
# File 'lib/sanitize_email/overridden_addresses.rb', line 143

def address_list_filter(list_type, address)
  # TODO: How does this handle email addresses with user names like "Foo Example <[email protected]>"
  has_address = send(list_type).include?(address)
  case list_type
  when :good_list then
    has_address ? address : nil
  when :bad_list then
    has_address ? nil : address
  else
    raise ArgumentError, "address_list_filter got unknown list_type: #{list_type}"
  end
end

#bcc_override(actual_addresses) ⇒ Object



86
87
88
# File 'lib/sanitize_email/overridden_addresses.rb', line 86

def bcc_override(actual_addresses)
  override_email(:bcc, actual_addresses).join(",")
end

#cc_override(actual_addresses) ⇒ Object



82
83
84
# File 'lib/sanitize_email/overridden_addresses.rb', line 82

def cc_override(actual_addresses)
  override_email(:cc, actual_addresses).join(",")
end

#clean_addresses(addresses, list_type) ⇒ Object



168
169
170
171
172
173
174
# File 'lib/sanitize_email/overridden_addresses.rb', line 168

def clean_addresses(addresses, list_type)
  # Normalize addresses just in case it isn't an array yet
  addresses.map do |address|
    # If this address is on the good list then let it pass
    address_list_filter(list_type, address)
  end.compact.uniq
end

#good_listize(real_addresses) ⇒ Object

Allow good listed email addresses, and then remove the bad listed addresses



71
72
73
74
75
# File 'lib/sanitize_email/overridden_addresses.rb', line 71

def good_listize(real_addresses)
  good_listed = clean_addresses(real_addresses, :good_list)
  good_listed = clean_addresses(good_listed, :bad_list) unless good_listed.empty?
  good_listed
end

#inject_user_names(real_addresses, sanitized_addresses) ⇒ Object



156
157
158
159
160
161
162
163
164
165
166
# File 'lib/sanitize_email/overridden_addresses.rb', line 156

def inject_user_names(real_addresses, sanitized_addresses)
  real_addresses.each_with_object([]) do |real_recipient, result|
    new_recipient = if real_recipient.nil?
      sanitized_addresses
    else
      # puts "SANITIZED: #{sanitized_addresses}"
      sanitized_addresses.map { |sanitized| "#{real_recipient.gsub(REPLACE_AT[0], REPLACE_AT[1]).gsub(/[<>]/, "~")} <#{sanitized}>" }
    end
    result << new_recipient
  end.flatten
end

#override_email(type, actual_addresses) ⇒ Object



107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
# File 'lib/sanitize_email/overridden_addresses.rb', line 107

def override_email(type, actual_addresses)
  # Normalized to an arrays
  # puts "override_email 1: #{type} - #{actual_addresses}"
  real_addresses = Array(actual_addresses)

  # puts "override_email 2: #{type} - #{real_addresses}"
  # If there were no original recipients, then we DO NOT override the nil with the sanitized recipients
  return [] if real_addresses.empty?

  good_listed = good_listize(real_addresses)
  # puts "override_email 3: #{type} - #{good_listed}"
  # If there are good_list addresses to send to then use them as is, no mods needed
  return good_listed unless good_listed.empty?

  # TODO: Allow overriding if an addressed email is on the good list?
  # If there are no sanitized addresses we can't override!
  sanitized_addresses = sanitize_addresses(type)
  # puts "override_email 4: #{type} - #{sanitized_addresses}"
  return [] if sanitized_addresses.empty?

  # At this point it is assured that the address list will need to be sanitized
  # One more check to ensure none of the configured sanitized email addresses are on the bad_list
  sanitized_addresses = clean_addresses(sanitized_addresses, :bad_list)
  # puts "override_email 5: #{type} - #{sanitized_addresses}"

  # If we don't want to inject the "email" in the "user name" section of the sanitized recipients,
  # then just return the default sanitized recipients
  return sanitized_addresses unless SanitizeEmail.use_actual_email_as_sanitized_user_name

  with_user_names = inject_user_names(real_addresses, sanitized_addresses)
  # puts "real_addresses 2: #{real_addresses}"
  # puts "override_email 6: #{type} - #{with_user_names}"
  # Otherwise inject the email as the "user name"
  with_user_names
end

#personalizations_override(actual_personalizations) ⇒ Object

Intended to result in compatibility with github.com/eddiezane/sendgrid-actionmailer



91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
# File 'lib/sanitize_email/overridden_addresses.rb', line 91

def personalizations_override(actual_personalizations)
  actual_personalizations.unparsed_value.map do |actual_personalization|
    actual_personalization.merge(
      to: actual_personalization[:to]&.map do |to|
        to.merge(email: override_email(:to, to[:email]).join(","))
      end,
      cc: actual_personalization[:cc]&.map do |cc|
        cc.merge(email: override_email(:cc, cc[:email]).join(","))
      end,
      bcc: actual_personalization[:bcc]&.map do |bcc|
        bcc.merge(email: override_email(:bcc, bcc[:email]).join(","))
      end,
    )
  end
end

#sanitize_addresses(type) ⇒ Object



176
177
178
179
180
181
182
183
184
185
186
187
# File 'lib/sanitize_email/overridden_addresses.rb', line 176

def sanitize_addresses(type)
  case type
  when :to then
    Array(sanitized_to)
  when :cc then
    Array(sanitized_cc)
  when :bcc then
    Array(sanitized_bcc)
  else
    raise UnknownOverride, "unknown email override"
  end
end

#to_override(actual_addresses) ⇒ Object



77
78
79
80
# File 'lib/sanitize_email/overridden_addresses.rb', line 77

def to_override(actual_addresses)
  to = override_email(:to, actual_addresses)
  to.join(",")
end