mail 2.5.5 → 2.8.1
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 +5 -5
- data/MIT-LICENSE +1 -1
- data/README.md +170 -108
- data/lib/mail/attachments_list.rb +13 -10
- data/lib/mail/body.rb +105 -91
- data/lib/mail/check_delivery_params.rb +30 -22
- data/lib/mail/configuration.rb +3 -0
- data/lib/mail/constants.rb +79 -0
- data/lib/mail/elements/address.rb +118 -174
- data/lib/mail/elements/address_list.rb +16 -56
- data/lib/mail/elements/content_disposition_element.rb +12 -22
- data/lib/mail/elements/content_location_element.rb +9 -17
- data/lib/mail/elements/content_transfer_encoding_element.rb +8 -19
- data/lib/mail/elements/content_type_element.rb +20 -30
- data/lib/mail/elements/date_time_element.rb +10 -21
- data/lib/mail/elements/envelope_from_element.rb +23 -31
- data/lib/mail/elements/message_ids_element.rb +22 -20
- data/lib/mail/elements/mime_version_element.rb +10 -21
- data/lib/mail/elements/phrase_list.rb +13 -15
- data/lib/mail/elements/received_element.rb +26 -21
- data/lib/mail/elements.rb +1 -0
- data/lib/mail/encodings/7bit.rb +10 -14
- data/lib/mail/encodings/8bit.rb +5 -18
- data/lib/mail/encodings/base64.rb +15 -10
- data/lib/mail/encodings/binary.rb +4 -22
- data/lib/mail/encodings/identity.rb +24 -0
- data/lib/mail/encodings/quoted_printable.rb +13 -7
- data/lib/mail/encodings/transfer_encoding.rb +47 -28
- data/lib/mail/encodings/unix_to_unix.rb +20 -0
- data/lib/mail/encodings.rb +102 -93
- data/lib/mail/envelope.rb +12 -19
- data/lib/mail/field.rb +143 -71
- data/lib/mail/field_list.rb +73 -19
- data/lib/mail/fields/bcc_field.rb +42 -48
- data/lib/mail/fields/cc_field.rb +29 -50
- data/lib/mail/fields/comments_field.rb +28 -37
- data/lib/mail/fields/common_address_field.rb +170 -0
- data/lib/mail/fields/common_date_field.rb +58 -0
- data/lib/mail/fields/common_field.rb +77 -0
- data/lib/mail/fields/common_message_id_field.rb +42 -0
- data/lib/mail/fields/content_description_field.rb +8 -14
- data/lib/mail/fields/content_disposition_field.rb +20 -44
- data/lib/mail/fields/content_id_field.rb +25 -51
- data/lib/mail/fields/content_location_field.rb +12 -25
- data/lib/mail/fields/content_transfer_encoding_field.rb +31 -36
- data/lib/mail/fields/content_type_field.rb +51 -80
- data/lib/mail/fields/date_field.rb +24 -52
- data/lib/mail/fields/from_field.rb +29 -50
- data/lib/mail/fields/in_reply_to_field.rb +39 -49
- data/lib/mail/fields/keywords_field.rb +19 -32
- data/lib/mail/fields/message_id_field.rb +26 -71
- data/lib/mail/fields/mime_version_field.rb +20 -30
- data/lib/mail/fields/named_structured_field.rb +11 -0
- data/lib/mail/fields/named_unstructured_field.rb +11 -0
- data/lib/mail/fields/optional_field.rb +10 -7
- data/lib/mail/fields/{common/parameter_hash.rb → parameter_hash.rb} +16 -13
- data/lib/mail/fields/received_field.rb +44 -57
- data/lib/mail/fields/references_field.rb +36 -49
- data/lib/mail/fields/reply_to_field.rb +29 -50
- data/lib/mail/fields/resent_bcc_field.rb +29 -50
- data/lib/mail/fields/resent_cc_field.rb +29 -50
- data/lib/mail/fields/resent_date_field.rb +6 -30
- data/lib/mail/fields/resent_from_field.rb +29 -50
- data/lib/mail/fields/resent_message_id_field.rb +6 -29
- data/lib/mail/fields/resent_sender_field.rb +28 -57
- data/lib/mail/fields/resent_to_field.rb +29 -50
- data/lib/mail/fields/return_path_field.rb +51 -55
- data/lib/mail/fields/sender_field.rb +35 -56
- data/lib/mail/fields/structured_field.rb +4 -30
- data/lib/mail/fields/subject_field.rb +10 -11
- data/lib/mail/fields/to_field.rb +29 -50
- data/lib/mail/fields/unstructured_field.rb +43 -51
- data/lib/mail/fields.rb +1 -0
- data/lib/mail/header.rb +78 -129
- data/lib/mail/indifferent_hash.rb +1 -0
- data/lib/mail/mail.rb +18 -11
- data/lib/mail/matchers/attachment_matchers.rb +44 -0
- data/lib/mail/matchers/has_sent_mail.rb +81 -4
- data/lib/mail/message.rb +142 -139
- data/lib/mail/multibyte/chars.rb +24 -180
- data/lib/mail/multibyte/unicode.rb +32 -27
- data/lib/mail/multibyte/utils.rb +27 -43
- data/lib/mail/multibyte.rb +56 -16
- data/lib/mail/network/delivery_methods/exim.rb +6 -4
- data/lib/mail/network/delivery_methods/file_delivery.rb +12 -10
- data/lib/mail/network/delivery_methods/logger_delivery.rb +34 -0
- data/lib/mail/network/delivery_methods/sendmail.rb +63 -21
- data/lib/mail/network/delivery_methods/smtp.rb +76 -50
- data/lib/mail/network/delivery_methods/smtp_connection.rb +4 -4
- data/lib/mail/network/delivery_methods/test_mailer.rb +5 -2
- data/lib/mail/network/retriever_methods/base.rb +9 -8
- data/lib/mail/network/retriever_methods/imap.rb +37 -18
- data/lib/mail/network/retriever_methods/pop3.rb +6 -3
- data/lib/mail/network/retriever_methods/test_retriever.rb +4 -2
- data/lib/mail/network.rb +2 -0
- data/lib/mail/parser_tools.rb +15 -0
- data/lib/mail/parsers/address_lists_parser.rb +33242 -0
- data/lib/mail/parsers/address_lists_parser.rl +179 -0
- data/lib/mail/parsers/content_disposition_parser.rb +901 -0
- data/lib/mail/parsers/content_disposition_parser.rl +89 -0
- data/lib/mail/parsers/content_location_parser.rb +822 -0
- data/lib/mail/parsers/content_location_parser.rl +78 -0
- data/lib/mail/parsers/content_transfer_encoding_parser.rb +522 -0
- data/lib/mail/parsers/content_transfer_encoding_parser.rl +71 -0
- data/lib/mail/parsers/content_type_parser.rb +1048 -0
- data/lib/mail/parsers/content_type_parser.rl +90 -0
- data/lib/mail/parsers/date_time_parser.rb +891 -0
- data/lib/mail/parsers/date_time_parser.rl +69 -0
- data/lib/mail/parsers/envelope_from_parser.rb +3675 -0
- data/lib/mail/parsers/envelope_from_parser.rl +89 -0
- data/lib/mail/parsers/message_ids_parser.rb +5161 -0
- data/lib/mail/parsers/message_ids_parser.rl +93 -0
- data/lib/mail/parsers/mime_version_parser.rb +513 -0
- data/lib/mail/parsers/mime_version_parser.rl +68 -0
- data/lib/mail/parsers/phrase_lists_parser.rb +884 -0
- data/lib/mail/parsers/phrase_lists_parser.rl +90 -0
- data/lib/mail/parsers/received_parser.rb +8782 -0
- data/lib/mail/parsers/received_parser.rl +91 -0
- data/lib/mail/parsers/rfc2045_content_transfer_encoding.rl +13 -0
- data/lib/mail/parsers/rfc2045_content_type.rl +25 -0
- data/lib/mail/parsers/rfc2045_mime.rl +16 -0
- data/lib/mail/parsers/rfc2183_content_disposition.rl +15 -0
- data/lib/mail/parsers/rfc3629_utf8.rl +19 -0
- data/lib/mail/parsers/rfc5234_abnf_core_rules.rl +22 -0
- data/lib/mail/parsers/rfc5322.rl +74 -0
- data/lib/mail/parsers/rfc5322_address.rl +72 -0
- data/lib/mail/parsers/rfc5322_date_time.rl +37 -0
- data/lib/mail/parsers/rfc5322_lexical_tokens.rl +60 -0
- data/lib/mail/parsers.rb +13 -0
- data/lib/mail/part.rb +11 -12
- data/lib/mail/parts_list.rb +90 -14
- data/lib/mail/smtp_envelope.rb +57 -0
- data/lib/mail/utilities.rb +415 -76
- data/lib/mail/values/unicode_tables.dat +0 -0
- data/lib/mail/version.rb +8 -15
- data/lib/mail/yaml.rb +30 -0
- data/lib/mail.rb +9 -32
- metadata +127 -79
- data/CHANGELOG.rdoc +0 -742
- data/CONTRIBUTING.md +0 -45
- data/Dependencies.txt +0 -3
- data/Gemfile +0 -32
- data/Rakefile +0 -21
- data/TODO.rdoc +0 -9
- data/lib/VERSION +0 -4
- data/lib/load_parsers.rb +0 -35
- data/lib/mail/core_extensions/nil.rb +0 -19
- data/lib/mail/core_extensions/object.rb +0 -13
- data/lib/mail/core_extensions/smtp.rb +0 -24
- data/lib/mail/core_extensions/string/access.rb +0 -145
- data/lib/mail/core_extensions/string/multibyte.rb +0 -78
- data/lib/mail/core_extensions/string.rb +0 -33
- data/lib/mail/fields/common/address_container.rb +0 -16
- data/lib/mail/fields/common/common_address.rb +0 -140
- data/lib/mail/fields/common/common_date.rb +0 -42
- data/lib/mail/fields/common/common_field.rb +0 -57
- data/lib/mail/fields/common/common_message_id.rb +0 -48
- data/lib/mail/multibyte/exceptions.rb +0 -8
- data/lib/mail/parsers/address_lists.rb +0 -64
- data/lib/mail/parsers/address_lists.treetop +0 -19
- data/lib/mail/parsers/content_disposition.rb +0 -535
- data/lib/mail/parsers/content_disposition.treetop +0 -46
- data/lib/mail/parsers/content_location.rb +0 -139
- data/lib/mail/parsers/content_location.treetop +0 -20
- data/lib/mail/parsers/content_transfer_encoding.rb +0 -201
- data/lib/mail/parsers/content_transfer_encoding.treetop +0 -18
- data/lib/mail/parsers/content_type.rb +0 -971
- data/lib/mail/parsers/content_type.treetop +0 -68
- data/lib/mail/parsers/date_time.rb +0 -114
- data/lib/mail/parsers/date_time.treetop +0 -11
- data/lib/mail/parsers/envelope_from.rb +0 -194
- data/lib/mail/parsers/envelope_from.treetop +0 -32
- data/lib/mail/parsers/message_ids.rb +0 -45
- data/lib/mail/parsers/message_ids.treetop +0 -15
- data/lib/mail/parsers/mime_version.rb +0 -144
- data/lib/mail/parsers/mime_version.treetop +0 -19
- data/lib/mail/parsers/phrase_lists.rb +0 -45
- data/lib/mail/parsers/phrase_lists.treetop +0 -15
- data/lib/mail/parsers/received.rb +0 -71
- data/lib/mail/parsers/received.treetop +0 -11
- data/lib/mail/parsers/rfc2045.rb +0 -421
- data/lib/mail/parsers/rfc2045.treetop +0 -35
- data/lib/mail/parsers/rfc2822.rb +0 -5397
- data/lib/mail/parsers/rfc2822.treetop +0 -408
- data/lib/mail/parsers/rfc2822_obsolete.rb +0 -3768
- data/lib/mail/parsers/rfc2822_obsolete.treetop +0 -241
- data/lib/mail/patterns.rb +0 -35
- data/lib/mail/version_specific/ruby_1_8.rb +0 -119
- data/lib/mail/version_specific/ruby_1_9.rb +0 -147
- data/lib/tasks/corpus.rake +0 -125
- data/lib/tasks/treetop.rake +0 -10
data/lib/mail/field.rb
CHANGED
@@ -1,4 +1,6 @@
|
|
1
|
+
# frozen_string_literal: true
|
1
2
|
require 'mail/fields'
|
3
|
+
require 'mail/constants'
|
2
4
|
|
3
5
|
# encoding: utf-8
|
4
6
|
module Mail
|
@@ -21,8 +23,6 @@ module Mail
|
|
21
23
|
# sections 3 and 4 of this standard.
|
22
24
|
#
|
23
25
|
class Field
|
24
|
-
|
25
|
-
include Patterns
|
26
26
|
include Comparable
|
27
27
|
|
28
28
|
STRUCTURED_FIELDS = %w[ bcc cc content-description content-disposition
|
@@ -67,6 +67,10 @@ module Mail
|
|
67
67
|
"content-location" => ContentLocationField,
|
68
68
|
}
|
69
69
|
|
70
|
+
FIELD_NAME_MAP = FIELDS_MAP.inject({}) do |map, (field, field_klass)|
|
71
|
+
map.update(field => field_klass::NAME)
|
72
|
+
end
|
73
|
+
|
70
74
|
# Generic Field Exception
|
71
75
|
class FieldError < StandardError
|
72
76
|
end
|
@@ -78,9 +82,31 @@ module Mail
|
|
78
82
|
|
79
83
|
def initialize(element, value, reason)
|
80
84
|
@element = element
|
81
|
-
@value = value
|
82
|
-
@reason = reason
|
83
|
-
super("#{element} can not parse |#{value}
|
85
|
+
@value = to_utf8(value)
|
86
|
+
@reason = to_utf8(reason)
|
87
|
+
super("#{@element} can not parse |#{@value}|: #{@reason}")
|
88
|
+
end
|
89
|
+
|
90
|
+
private
|
91
|
+
def to_utf8(text)
|
92
|
+
if text.respond_to?(:force_encoding)
|
93
|
+
text.dup.force_encoding(Encoding::UTF_8)
|
94
|
+
else
|
95
|
+
text
|
96
|
+
end
|
97
|
+
end
|
98
|
+
end
|
99
|
+
|
100
|
+
class NilParseError < ParseError #:nodoc:
|
101
|
+
def initialize(element)
|
102
|
+
super element, nil, 'nil is invalid'
|
103
|
+
end
|
104
|
+
end
|
105
|
+
|
106
|
+
class IncompleteParseError < ParseError #:nodoc:
|
107
|
+
def initialize(element, original_text, unparsed_index)
|
108
|
+
parsed_text = to_utf8(original_text[0...unparsed_index])
|
109
|
+
super element, original_text, "Only able to parse up to #{parsed_text.inspect}"
|
84
110
|
end
|
85
111
|
end
|
86
112
|
|
@@ -88,49 +114,81 @@ module Mail
|
|
88
114
|
class SyntaxError < FieldError #:nodoc:
|
89
115
|
end
|
90
116
|
|
91
|
-
|
92
|
-
|
93
|
-
|
94
|
-
|
95
|
-
|
96
|
-
|
97
|
-
|
117
|
+
class << self
|
118
|
+
# Parse a field from a raw header line:
|
119
|
+
#
|
120
|
+
# Mail::Field.parse("field-name: field data")
|
121
|
+
# # => #<Mail::Field …>
|
122
|
+
def parse(field, charset = 'utf-8')
|
123
|
+
name, value = split(field)
|
124
|
+
if name && value
|
125
|
+
new name, value, charset
|
126
|
+
end
|
127
|
+
end
|
128
|
+
|
129
|
+
def split(raw_field) #:nodoc:
|
130
|
+
if raw_field.index(Constants::COLON)
|
131
|
+
name, value = raw_field.split(Constants::COLON, 2)
|
132
|
+
name.rstrip!
|
133
|
+
if name =~ /\A#{Constants::FIELD_NAME}\z/
|
134
|
+
[ name.rstrip, value.strip ]
|
135
|
+
else
|
136
|
+
Kernel.warn "WARNING: Ignoring unparsable header #{raw_field.inspect}: invalid header name syntax: #{name.inspect}"
|
137
|
+
nil
|
138
|
+
end
|
139
|
+
else
|
140
|
+
raw_field.strip
|
141
|
+
end
|
142
|
+
rescue => error
|
143
|
+
warn "WARNING: Ignoring unparsable header #{raw_field.inspect}: #{error.class}: #{error.message}"
|
144
|
+
nil
|
145
|
+
end
|
146
|
+
|
147
|
+
def field_class_for(name) #:nodoc:
|
148
|
+
FIELDS_MAP[name.to_s.downcase]
|
149
|
+
end
|
150
|
+
end
|
151
|
+
|
152
|
+
attr_reader :unparsed_value
|
153
|
+
|
154
|
+
# Create a field by name and optional value:
|
98
155
|
#
|
99
|
-
#
|
156
|
+
# Mail::Field.new("field-name", "value")
|
157
|
+
# # => #<Mail::Field …>
|
100
158
|
#
|
101
|
-
#
|
159
|
+
# Values that aren't strings or arrays are coerced to Strings with `#to_s`.
|
102
160
|
#
|
103
|
-
#
|
104
|
-
#
|
105
|
-
# it will be passed through as is, for example, content-type
|
106
|
-
# field can accept an array with the type and a hash of
|
107
|
-
# parameters:
|
161
|
+
# Mail::Field.new("field-name", 1234)
|
162
|
+
# # => #<Mail::Field …>
|
108
163
|
#
|
109
|
-
# Field.new('content-type', ['text', 'plain', {:charset => 'UTF-8'}])
|
164
|
+
# Mail::Field.new('content-type', ['text', 'plain', {:charset => 'UTF-8'}])
|
165
|
+
# # => #<Mail::Field …>
|
110
166
|
def initialize(name, value = nil, charset = 'utf-8')
|
111
167
|
case
|
112
|
-
when name
|
113
|
-
|
114
|
-
|
115
|
-
|
116
|
-
|
117
|
-
|
118
|
-
else
|
119
|
-
|
168
|
+
when name.index(Constants::COLON)
|
169
|
+
raise ArgumentError, 'Passing an unparsed header field to Mail::Field.new is not supported in Mail 2.8.0+. Use Mail::Field.parse instead.'
|
170
|
+
when Utilities.blank?(value)
|
171
|
+
@name = name
|
172
|
+
@unparsed_value = nil
|
173
|
+
@charset = charset
|
174
|
+
else
|
175
|
+
@name = name
|
176
|
+
@unparsed_value = value
|
177
|
+
@charset = charset
|
120
178
|
end
|
121
|
-
|
179
|
+
@name = FIELD_NAME_MAP[@name.to_s.downcase] || @name
|
122
180
|
end
|
123
181
|
|
124
|
-
def field=(
|
125
|
-
@field =
|
182
|
+
def field=(field)
|
183
|
+
@field = field
|
126
184
|
end
|
127
185
|
|
128
186
|
def field
|
129
|
-
@field
|
187
|
+
@field ||= create_field(@name, @unparsed_value, @charset)
|
130
188
|
end
|
131
189
|
|
132
190
|
def name
|
133
|
-
|
191
|
+
@name
|
134
192
|
end
|
135
193
|
|
136
194
|
def value
|
@@ -138,74 +196,88 @@ module Mail
|
|
138
196
|
end
|
139
197
|
|
140
198
|
def value=(val)
|
141
|
-
create_field(name, val, charset)
|
199
|
+
@field = create_field(name, val, @charset)
|
142
200
|
end
|
143
201
|
|
144
202
|
def to_s
|
145
203
|
field.to_s
|
146
204
|
end
|
147
205
|
|
148
|
-
def
|
149
|
-
|
206
|
+
def inspect
|
207
|
+
"#<#{self.class.name} 0x#{(object_id * 2).to_s(16)} #{instance_variables.map do |ivar|
|
208
|
+
"#{ivar}=#{instance_variable_get(ivar).inspect}"
|
209
|
+
end.join(" ")}>"
|
210
|
+
end
|
211
|
+
|
212
|
+
def same(other)
|
213
|
+
other.kind_of?(self.class) && Utilities.match_to_s(other.name, name)
|
150
214
|
end
|
151
215
|
|
152
|
-
def
|
153
|
-
match_to_s(other.
|
216
|
+
def ==(other)
|
217
|
+
same(other) && Utilities.match_to_s(other.value, value)
|
154
218
|
end
|
155
219
|
|
156
|
-
|
220
|
+
def responsible_for?(field_name)
|
221
|
+
name.to_s.casecmp(field_name.to_s) == 0
|
222
|
+
end
|
157
223
|
|
158
|
-
def <=>(
|
159
|
-
|
224
|
+
def <=>(other)
|
225
|
+
field_order_id <=> other.field_order_id
|
160
226
|
end
|
161
227
|
|
162
228
|
def field_order_id
|
163
|
-
@field_order_id ||= (
|
229
|
+
@field_order_id ||= FIELD_ORDER_LOOKUP.fetch(self.name.to_s.downcase, 100)
|
164
230
|
end
|
165
231
|
|
166
232
|
def method_missing(name, *args, &block)
|
167
233
|
field.send(name, *args, &block)
|
168
234
|
end
|
169
235
|
|
170
|
-
|
171
|
-
|
172
|
-
|
173
|
-
date from sender reply-to to cc bcc
|
174
|
-
message-id in-reply-to references
|
175
|
-
subject comments keywords
|
176
|
-
mime-version content-type content-transfer-encoding
|
177
|
-
content-location content-disposition content-description ]
|
236
|
+
def respond_to_missing?(method_name, include_private)
|
237
|
+
field.respond_to?(method_name, include_private) || super
|
238
|
+
end
|
178
239
|
|
179
|
-
FIELD_ORDER_LOOKUP = Hash[
|
240
|
+
FIELD_ORDER_LOOKUP = Hash[%w[
|
241
|
+
return-path received
|
242
|
+
resent-date resent-from resent-sender resent-to
|
243
|
+
resent-cc resent-bcc resent-message-id
|
244
|
+
date from sender reply-to to cc bcc
|
245
|
+
message-id in-reply-to references
|
246
|
+
subject comments keywords
|
247
|
+
mime-version content-type content-transfer-encoding
|
248
|
+
content-location content-disposition content-description
|
249
|
+
].each_with_index.to_a]
|
180
250
|
|
181
251
|
private
|
182
252
|
|
183
|
-
def split(raw_field)
|
184
|
-
match_data = raw_field.mb_chars.match(FIELD_SPLIT)
|
185
|
-
[match_data[1].to_s.mb_chars.strip, match_data[2].to_s.mb_chars.strip]
|
186
|
-
rescue
|
187
|
-
STDERR.puts "WARNING: Could not parse (and so ignoring) '#{raw_field}'"
|
188
|
-
end
|
189
|
-
|
190
253
|
def create_field(name, value, charset)
|
191
|
-
|
192
|
-
|
193
|
-
|
194
|
-
|
195
|
-
|
196
|
-
self.field
|
197
|
-
end
|
254
|
+
parse_field(name, value, charset)
|
255
|
+
rescue Mail::Field::ParseError => e
|
256
|
+
field = Mail::UnstructuredField.new(name, value)
|
257
|
+
field.errors << [name, value, e]
|
258
|
+
field
|
198
259
|
end
|
199
260
|
|
200
|
-
def
|
201
|
-
|
202
|
-
|
203
|
-
|
261
|
+
def parse_field(name, value, charset)
|
262
|
+
value = unfold(value) if value.is_a?(String)
|
263
|
+
|
264
|
+
if klass = self.class.field_class_for(name)
|
265
|
+
klass.parse(value, charset)
|
204
266
|
else
|
205
|
-
OptionalField.
|
267
|
+
OptionalField.parse(name, value, charset)
|
206
268
|
end
|
207
269
|
end
|
208
270
|
|
271
|
+
# 2.2.3. Long Header Fields
|
272
|
+
#
|
273
|
+
# The process of moving from this folded multiple-line representation
|
274
|
+
# of a header field to its single line representation is called
|
275
|
+
# "unfolding". Unfolding is accomplished by simply removing any CRLF
|
276
|
+
# that is immediately followed by WSP. Each header field should be
|
277
|
+
# treated in its unfolded form for further syntactic and semantic
|
278
|
+
# evaluation.
|
279
|
+
def unfold(string)
|
280
|
+
string.gsub(Constants::UNFOLD_WS, '\1')
|
281
|
+
end
|
209
282
|
end
|
210
|
-
|
211
283
|
end
|
data/lib/mail/field_list.rb
CHANGED
@@ -1,33 +1,87 @@
|
|
1
1
|
# encoding: utf-8
|
2
|
+
# frozen_string_literal: true
|
2
3
|
module Mail
|
3
4
|
|
4
5
|
# Field List class provides an enhanced array that keeps a list of
|
5
6
|
# email fields in order. And allows you to insert new fields without
|
6
7
|
# having to worry about the order they will appear in.
|
7
8
|
class FieldList < Array
|
9
|
+
def has_field?(field_name)
|
10
|
+
any? { |f| f.responsible_for? field_name }
|
11
|
+
end
|
12
|
+
|
13
|
+
def get_field(field_name)
|
14
|
+
fields = select_fields(field_name)
|
15
|
+
case fields.size
|
16
|
+
when 0; nil
|
17
|
+
when 1; fields.first
|
18
|
+
else fields
|
19
|
+
end
|
20
|
+
end
|
8
21
|
|
9
|
-
|
22
|
+
def add_field(field)
|
23
|
+
if field.singular?
|
24
|
+
replace_field field
|
25
|
+
else
|
26
|
+
insert_field field
|
27
|
+
end
|
28
|
+
end
|
29
|
+
alias_method :<<, :add_field
|
10
30
|
|
11
|
-
def
|
12
|
-
|
13
|
-
|
14
|
-
|
31
|
+
def replace_field(field)
|
32
|
+
if first_offset = index { |f| f.responsible_for? field.name }
|
33
|
+
delete_field field.name
|
34
|
+
insert first_offset, field
|
15
35
|
else
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
36
|
+
insert_field field
|
37
|
+
end
|
38
|
+
end
|
39
|
+
|
40
|
+
# Insert the field in sorted order.
|
41
|
+
#
|
42
|
+
# Heavily based on bisect.insort from Python, which is:
|
43
|
+
# Copyright (C) 2001-2013 Python Software Foundation.
|
44
|
+
# Licensed under <http://docs.python.org/license.html>
|
45
|
+
# From <http://hg.python.org/cpython/file/2.7/Lib/bisect.py>
|
46
|
+
def insert_field(field)
|
47
|
+
lo, hi = 0, size
|
48
|
+
while lo < hi
|
49
|
+
mid = (lo + hi).div(2)
|
50
|
+
if field < self[mid]
|
51
|
+
hi = mid
|
52
|
+
else
|
53
|
+
lo = mid + 1
|
27
54
|
end
|
28
|
-
|
55
|
+
end
|
56
|
+
|
57
|
+
insert lo, field
|
58
|
+
end
|
59
|
+
|
60
|
+
def delete_field(name)
|
61
|
+
delete_if { |f| f.responsible_for? name }
|
62
|
+
end
|
63
|
+
|
64
|
+
def summary
|
65
|
+
map { |f| "<#{f.name}: #{f.value}>" }.join(", ")
|
66
|
+
end
|
67
|
+
|
68
|
+
private
|
69
|
+
|
70
|
+
def select_fields(field_name)
|
71
|
+
fields = select { |f| f.responsible_for? field_name }
|
72
|
+
if fields.size > 1 && singular?(field_name)
|
73
|
+
Array(fields.detect { |f| f.errors.size == 0 } || fields.first)
|
74
|
+
else
|
75
|
+
fields
|
76
|
+
end
|
77
|
+
end
|
78
|
+
|
79
|
+
def singular?(field_name)
|
80
|
+
if klass = Mail::Field.field_class_for(field_name)
|
81
|
+
klass.singular?
|
82
|
+
else
|
83
|
+
false
|
29
84
|
end
|
30
85
|
end
|
31
|
-
|
32
86
|
end
|
33
|
-
end
|
87
|
+
end
|
@@ -1,56 +1,50 @@
|
|
1
1
|
# encoding: utf-8
|
2
|
-
#
|
3
|
-
|
4
|
-
#
|
5
|
-
# The Bcc field inherits from StructuredField and handles the Bcc: header
|
6
|
-
# field in the email.
|
7
|
-
#
|
8
|
-
# Sending bcc to a mail message will instantiate a Mail::Field object that
|
9
|
-
# has a BccField as its field type. This includes all Mail::CommonAddress
|
10
|
-
# module instance metods.
|
11
|
-
#
|
12
|
-
# Only one Bcc field can appear in a header, though it can have multiple
|
13
|
-
# addresses and groups of addresses.
|
14
|
-
#
|
15
|
-
# == Examples:
|
16
|
-
#
|
17
|
-
# mail = Mail.new
|
18
|
-
# mail.bcc = 'Mikel Lindsaar <mikel@test.lindsaar.net>, ada@test.lindsaar.net'
|
19
|
-
# mail.bcc #=> ['mikel@test.lindsaar.net', 'ada@test.lindsaar.net']
|
20
|
-
# mail[:bcc] #=> '#<Mail::Field:0x180e5e8 @field=#<Mail::BccField:0x180e1c4
|
21
|
-
# mail['bcc'] #=> '#<Mail::Field:0x180e5e8 @field=#<Mail::BccField:0x180e1c4
|
22
|
-
# mail['Bcc'] #=> '#<Mail::Field:0x180e5e8 @field=#<Mail::BccField:0x180e1c4
|
23
|
-
#
|
24
|
-
# mail[:bcc].encoded #=> '' # Bcc field does not get output into an email
|
25
|
-
# mail[:bcc].decoded #=> 'Mikel Lindsaar <mikel@test.lindsaar.net>, ada@test.lindsaar.net'
|
26
|
-
# mail[:bcc].addresses #=> ['mikel@test.lindsaar.net', 'ada@test.lindsaar.net']
|
27
|
-
# mail[:bcc].formatted #=> ['Mikel Lindsaar <mikel@test.lindsaar.net>', 'ada@test.lindsaar.net']
|
28
|
-
#
|
29
|
-
require 'mail/fields/common/common_address'
|
2
|
+
# frozen_string_literal: true
|
3
|
+
require 'mail/fields/common_address_field'
|
30
4
|
|
31
5
|
module Mail
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
|
39
|
-
|
40
|
-
|
41
|
-
|
42
|
-
|
43
|
-
|
6
|
+
# = Blind Carbon Copy Field
|
7
|
+
#
|
8
|
+
# The Bcc field inherits from StructuredField and handles the Bcc: header
|
9
|
+
# field in the email.
|
10
|
+
#
|
11
|
+
# Sending bcc to a mail message will instantiate a Mail::Field object that
|
12
|
+
# has a BccField as its field type. This includes all Mail::CommonAddress
|
13
|
+
# module instance metods.
|
14
|
+
#
|
15
|
+
# Only one Bcc field can appear in a header, though it can have multiple
|
16
|
+
# addresses and groups of addresses.
|
17
|
+
#
|
18
|
+
# == Examples:
|
19
|
+
#
|
20
|
+
# mail = Mail.new
|
21
|
+
# mail.bcc = 'Mikel Lindsaar <mikel@test.lindsaar.net>, ada@test.lindsaar.net'
|
22
|
+
# mail.bcc #=> ['mikel@test.lindsaar.net', 'ada@test.lindsaar.net']
|
23
|
+
# mail[:bcc] #=> '#<Mail::Field:0x180e5e8 @field=#<Mail::BccField:0x180e1c4
|
24
|
+
# mail['bcc'] #=> '#<Mail::Field:0x180e5e8 @field=#<Mail::BccField:0x180e1c4
|
25
|
+
# mail['Bcc'] #=> '#<Mail::Field:0x180e5e8 @field=#<Mail::BccField:0x180e1c4
|
26
|
+
#
|
27
|
+
# mail[:bcc].encoded #=> '' # Bcc field does not get output into an email
|
28
|
+
# mail[:bcc].decoded #=> 'Mikel Lindsaar <mikel@test.lindsaar.net>, ada@test.lindsaar.net'
|
29
|
+
# mail[:bcc].addresses #=> ['mikel@test.lindsaar.net', 'ada@test.lindsaar.net']
|
30
|
+
# mail[:bcc].formatted #=> ['Mikel Lindsaar <mikel@test.lindsaar.net>', 'ada@test.lindsaar.net']
|
31
|
+
class BccField < CommonAddressField #:nodoc:
|
32
|
+
NAME = 'Bcc'
|
33
|
+
|
34
|
+
attr_accessor :include_in_headers
|
35
|
+
|
36
|
+
def initialize(value = nil, charset = nil)
|
37
|
+
super
|
38
|
+
self.include_in_headers = false
|
44
39
|
end
|
45
|
-
|
46
|
-
# Bcc field should
|
40
|
+
|
41
|
+
# Bcc field should not be :encoded by default
|
47
42
|
def encoded
|
48
|
-
|
49
|
-
|
50
|
-
|
51
|
-
|
52
|
-
|
43
|
+
if include_in_headers
|
44
|
+
super
|
45
|
+
else
|
46
|
+
''
|
47
|
+
end
|
53
48
|
end
|
54
|
-
|
55
49
|
end
|
56
50
|
end
|
data/lib/mail/fields/cc_field.rb
CHANGED
@@ -1,55 +1,34 @@
|
|
1
1
|
# encoding: utf-8
|
2
|
-
#
|
3
|
-
|
4
|
-
#
|
5
|
-
# The Cc field inherits from StructuredField and handles the Cc: header
|
6
|
-
# field in the email.
|
7
|
-
#
|
8
|
-
# Sending cc to a mail message will instantiate a Mail::Field object that
|
9
|
-
# has a CcField as its field type. This includes all Mail::CommonAddress
|
10
|
-
# module instance metods.
|
11
|
-
#
|
12
|
-
# Only one Cc field can appear in a header, though it can have multiple
|
13
|
-
# addresses and groups of addresses.
|
14
|
-
#
|
15
|
-
# == Examples:
|
16
|
-
#
|
17
|
-
# mail = Mail.new
|
18
|
-
# mail.cc = 'Mikel Lindsaar <mikel@test.lindsaar.net>, ada@test.lindsaar.net'
|
19
|
-
# mail.cc #=> ['mikel@test.lindsaar.net', 'ada@test.lindsaar.net']
|
20
|
-
# mail[:cc] #=> '#<Mail::Field:0x180e5e8 @field=#<Mail::CcField:0x180e1c4
|
21
|
-
# mail['cc'] #=> '#<Mail::Field:0x180e5e8 @field=#<Mail::CcField:0x180e1c4
|
22
|
-
# mail['Cc'] #=> '#<Mail::Field:0x180e5e8 @field=#<Mail::CcField:0x180e1c4
|
23
|
-
#
|
24
|
-
# mail[:cc].encoded #=> 'Cc: Mikel Lindsaar <mikel@test.lindsaar.net>, ada@test.lindsaar.net\r\n'
|
25
|
-
# mail[:cc].decoded #=> 'Mikel Lindsaar <mikel@test.lindsaar.net>, ada@test.lindsaar.net'
|
26
|
-
# mail[:cc].addresses #=> ['mikel@test.lindsaar.net', 'ada@test.lindsaar.net']
|
27
|
-
# mail[:cc].formatted #=> ['Mikel Lindsaar <mikel@test.lindsaar.net>', 'ada@test.lindsaar.net']
|
28
|
-
#
|
29
|
-
require 'mail/fields/common/common_address'
|
2
|
+
# frozen_string_literal: true
|
3
|
+
require 'mail/fields/common_address_field'
|
30
4
|
|
31
5
|
module Mail
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
|
39
|
-
|
40
|
-
|
41
|
-
|
42
|
-
|
43
|
-
|
44
|
-
|
45
|
-
|
46
|
-
|
47
|
-
|
48
|
-
|
49
|
-
|
50
|
-
|
51
|
-
|
52
|
-
|
53
|
-
|
6
|
+
# = Carbon Copy Field
|
7
|
+
#
|
8
|
+
# The Cc field inherits from StructuredField and handles the Cc: header
|
9
|
+
# field in the email.
|
10
|
+
#
|
11
|
+
# Sending cc to a mail message will instantiate a Mail::Field object that
|
12
|
+
# has a CcField as its field type. This includes all Mail::CommonAddress
|
13
|
+
# module instance metods.
|
14
|
+
#
|
15
|
+
# Only one Cc field can appear in a header, though it can have multiple
|
16
|
+
# addresses and groups of addresses.
|
17
|
+
#
|
18
|
+
# == Examples:
|
19
|
+
#
|
20
|
+
# mail = Mail.new
|
21
|
+
# mail.cc = 'Mikel Lindsaar <mikel@test.lindsaar.net>, ada@test.lindsaar.net'
|
22
|
+
# mail.cc #=> ['mikel@test.lindsaar.net', 'ada@test.lindsaar.net']
|
23
|
+
# mail[:cc] #=> '#<Mail::Field:0x180e5e8 @field=#<Mail::CcField:0x180e1c4
|
24
|
+
# mail['cc'] #=> '#<Mail::Field:0x180e5e8 @field=#<Mail::CcField:0x180e1c4
|
25
|
+
# mail['Cc'] #=> '#<Mail::Field:0x180e5e8 @field=#<Mail::CcField:0x180e1c4
|
26
|
+
#
|
27
|
+
# mail[:cc].encoded #=> 'Cc: Mikel Lindsaar <mikel@test.lindsaar.net>, ada@test.lindsaar.net\r\n'
|
28
|
+
# mail[:cc].decoded #=> 'Mikel Lindsaar <mikel@test.lindsaar.net>, ada@test.lindsaar.net'
|
29
|
+
# mail[:cc].addresses #=> ['mikel@test.lindsaar.net', 'ada@test.lindsaar.net']
|
30
|
+
# mail[:cc].formatted #=> ['Mikel Lindsaar <mikel@test.lindsaar.net>', 'ada@test.lindsaar.net']
|
31
|
+
class CcField < CommonAddressField #:nodoc:
|
32
|
+
NAME = 'Cc'
|
54
33
|
end
|
55
34
|
end
|
@@ -1,41 +1,32 @@
|
|
1
1
|
# encoding: utf-8
|
2
|
-
#
|
3
|
-
|
4
|
-
|
5
|
-
# The Comments field inherits from UnstructuredField and handles the Comments:
|
6
|
-
# header field in the email.
|
7
|
-
#
|
8
|
-
# Sending comments to a mail message will instantiate a Mail::Field object that
|
9
|
-
# has a CommentsField as its field type.
|
10
|
-
#
|
11
|
-
# An email header can have as many comments fields as it wants. There is no upper
|
12
|
-
# limit, the comments field is also optional (that is, no comment is needed)
|
13
|
-
#
|
14
|
-
# == Examples:
|
15
|
-
#
|
16
|
-
# mail = Mail.new
|
17
|
-
# mail.comments = 'This is a comment'
|
18
|
-
# mail.comments #=> 'This is a comment'
|
19
|
-
# mail[:comments] #=> '#<Mail::Field:0x180e5e8 @field=#<Mail::CommentsField:0x180e1c4
|
20
|
-
# mail['comments'] #=> '#<Mail::Field:0x180e5e8 @field=#<Mail::CommentsField:0x180e1c4
|
21
|
-
# mail['comments'] #=> '#<Mail::Field:0x180e5e8 @field=#<Mail::CommentsField:0x180e1c4
|
22
|
-
#
|
23
|
-
# mail.comments = "This is another comment"
|
24
|
-
# mail[:comments].map { |c| c.to_s }
|
25
|
-
# #=> ['This is a comment', "This is another comment"]
|
26
|
-
#
|
2
|
+
# frozen_string_literal: true
|
3
|
+
require 'mail/fields/named_unstructured_field'
|
4
|
+
|
27
5
|
module Mail
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
|
39
|
-
|
6
|
+
# = Comments Field
|
7
|
+
#
|
8
|
+
# The Comments field inherits from UnstructuredField and handles the Comments:
|
9
|
+
# header field in the email.
|
10
|
+
#
|
11
|
+
# Sending comments to a mail message will instantiate a Mail::Field object that
|
12
|
+
# has a CommentsField as its field type.
|
13
|
+
#
|
14
|
+
# An email header can have as many comments fields as it wants. There is no upper
|
15
|
+
# limit, the comments field is also optional (that is, no comment is needed)
|
16
|
+
#
|
17
|
+
# == Examples:
|
18
|
+
#
|
19
|
+
# mail = Mail.new
|
20
|
+
# mail.comments = 'This is a comment'
|
21
|
+
# mail.comments #=> 'This is a comment'
|
22
|
+
# mail[:comments] #=> '#<Mail::Field:0x180e5e8 @field=#<Mail::CommentsField:0x180e1c4
|
23
|
+
# mail['comments'] #=> '#<Mail::Field:0x180e5e8 @field=#<Mail::CommentsField:0x180e1c4
|
24
|
+
# mail['comments'] #=> '#<Mail::Field:0x180e5e8 @field=#<Mail::CommentsField:0x180e1c4
|
25
|
+
#
|
26
|
+
# mail.comments = "This is another comment"
|
27
|
+
# mail[:comments].map { |c| c.to_s }
|
28
|
+
# #=> ['This is a comment', "This is another comment"]
|
29
|
+
class CommentsField < NamedUnstructuredField #:nodoc:
|
30
|
+
NAME = 'Comments'
|
40
31
|
end
|
41
32
|
end
|