Class: Mail::Field

Inherits:
Object
  • Object
show all
Includes:
Comparable
Defined in:
lib/mail/field.rb

Overview

Provides a single class to call to create a new structured or unstructured field. Works out per RFC what field of field it is being given and returns the correct field of class back on new.

===Per RFC 2822

2.2. Header Fields

Header fields are lines composed of a field name, followed by a colon
(":"), followed by a field body, and terminated by CRLF.  A field
name MUST be composed of printable US-ASCII characters (i.e.,
characters that have values between 33 and 126, inclusive), except
colon.  A field body may be composed of any US-ASCII characters,
except for CR and LF.  However, a field body may contain CRLF when
used in header "folding" and  "unfolding" as described in section
2.2.3.  All field bodies MUST conform to the syntax described in
sections 3 and 4 of this standard.

Defined Under Namespace

Classes: FieldError, IncompleteParseError, NilParseError, ParseError, SyntaxError

Constant Summary collapse

STRUCTURED_FIELDS =
%w[ bcc cc content-description content-disposition
content-id content-location content-transfer-encoding
content-type date from in-reply-to keywords message-id
mime-version received references reply-to
resent-bcc resent-cc resent-date resent-from
resent-message-id resent-sender resent-to
return-path sender to ]
KNOWN_FIELDS =
STRUCTURED_FIELDS + ['comments', 'subject']
FIELDS_MAP =
{
  "to" => "ToField",
  "cc" => "CcField",
  "bcc" => "BccField",
  "message-id" => "MessageIdField",
  "in-reply-to" => "InReplyToField",
  "references" => "ReferencesField",
  "subject" => "SubjectField",
  "comments" => "CommentsField",
  "keywords" => "KeywordsField",
  "date" => "DateField",
  "from" => "FromField",
  "sender" => "SenderField",
  "reply-to" => "ReplyToField",
  "resent-date" => "ResentDateField",
  "resent-from" => "ResentFromField",
  "resent-sender" => "ResentSenderField",
  "resent-to" => "ResentToField",
  "resent-cc" => "ResentCcField",
  "resent-bcc" => "ResentBccField",
  "resent-message-id" => "ResentMessageIdField",
  "return-path" => "ReturnPathField",
  "received" => "ReceivedField",
  "mime-version" => "MimeVersionField",
  "content-transfer-encoding" => "ContentTransferEncodingField",
  "content-description" => "ContentDescriptionField",
  "content-disposition" => "ContentDispositionField",
  "content-type" => "ContentTypeField",
  "content-id" => "ContentIdField",
  "content-location" => "ContentLocationField",
}
FIELD_NAME_MAP =
{
  "to" => "To",
  "cc" => "Cc",
  "bcc" => "Bcc",
  "message-id" => "Message-ID",
  "in-reply-to" => "In-Reply-To",
  "references" => "References",
  "subject" => "Subject",
  "comments" => "Comments",
  "keywords" => "Keywords",
  "date" => "Date",
  "from" => "From",
  "sender" => "Sender",
  "reply-to" => "Reply-To",
  "resent-date" => "Resent-Date",
  "resent-from" => "Resent-From",
  "resent-sender" => "Resent-Sender",
  "resent-to" => "Resent-To",
  "resent-cc" => "Resent-Cc",
  "resent-bcc" => "Resent-Bcc",
  "resent-message-id" => "Resent-Message-ID",
  "return-path" => "Return-Path",
  "received" => "Received",
  "mime-version" => "MIME-Version",
  "content-transfer-encoding" => "Content-Transfer-Encoding",
  "content-description" => "Content-Description",
  "content-disposition" => "Content-Disposition",
  "content-type" => "Content-Type",
  "content-id" => "Content-ID",
  "content-location" => "Content-Location",
}
FIELD_ORDER_LOOKUP =

Instance Attribute Summary collapse

Class Method Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(name, value = nil, charset = 'utf-8') ⇒ Field

Create a field by name and optional value:

Mail::Field.new("field-name", "value")

=> #<Mail::Field …>

Values that aren't strings or arrays are coerced to Strings with #to_s.

Mail::Field.new("field-name", 1234)

=> #<Mail::Field …>

Mail::Field.new('content-type', ['text', 'plain', => 'UTF-8'])

=> #<Mail::Field …>



195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
# File 'lib/mail/field.rb', line 195

def initialize(name, value = nil, charset = 'utf-8')
  case
  when name.index(Constants::COLON)
    raise ArgumentError, 'Passing an unparsed header field to Mail::Field.new is not supported in Mail 2.8.0+. Use Mail::Field.parse instead.'
  when Utilities.blank?(value)
    @name = name
    @unparsed_value = nil
    @charset = charset
  else
    @name = name
    @unparsed_value = value
    @charset = charset
  end
  klass = self.class.field_class_for(@name)
  @name = klass ? klass::NAME : @name
end

Dynamic Method Handling

This class handles dynamic methods through the method_missing method

#method_missing(name, *args, &block) ⇒ Object



262
263
264
# File 'lib/mail/field.rb', line 262

def method_missing(name, *args, &block)
  field.send(name, *args, &block)
end

Instance Attribute Details

#unparsed_valueObject (readonly)

Returns the value of attribute unparsed_value.



181
182
183
# File 'lib/mail/field.rb', line 181

def unparsed_value
  @unparsed_value
end

Class Method Details

.field_class_for(name) ⇒ Object

:nodoc:



175
176
177
178
# File 'lib/mail/field.rb', line 175

def field_class_for(name) #:nodoc:
  class_name = FIELDS_MAP[name.to_s.downcase]
  Mail.const_get(class_name) if class_name
end

.parse(field, charset = 'utf-8') ⇒ Object

Parse a field from a raw header line:

Mail::Field.parse("field-name: field data")

=> #<Mail::Field …>



150
151
152
153
154
155
# File 'lib/mail/field.rb', line 150

def parse(field, charset = 'utf-8')
  name, value = split(field)
  if name && value
    new name, value, charset
  end
end

.split(raw_field) ⇒ Object

:nodoc:



157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
# File 'lib/mail/field.rb', line 157

def split(raw_field) #:nodoc:
  if raw_field.index(Constants::COLON)
    name, value = raw_field.split(Constants::COLON, 2)
    name.rstrip!
    if /\A#{Constants::FIELD_NAME}\z/.match?(name)
      [ name.rstrip, value.strip ]
    else
      Kernel.warn "WARNING: Ignoring unparsable header #{raw_field.inspect}: invalid header name syntax: #{name.inspect}"
      nil
    end
  else
    raw_field.strip
  end
rescue => error
  warn "WARNING: Ignoring unparsable header #{raw_field.inspect}: #{error.class}: #{error.message}"
  nil
end

Instance Method Details

#<=>(other) ⇒ Object



254
255
256
# File 'lib/mail/field.rb', line 254

def <=>(other)
  field_order_id <=> other.field_order_id
end

#==(other) ⇒ Object



246
247
248
# File 'lib/mail/field.rb', line 246

def ==(other)
  same(other) && Utilities.match_to_s(other.value, value)
end

#fieldObject



216
217
218
# File 'lib/mail/field.rb', line 216

def field
  @field ||= create_field(@name, @unparsed_value, @charset)
end

#field=(field) ⇒ Object



212
213
214
# File 'lib/mail/field.rb', line 212

def field=(field)
  @field = field
end

#field_order_idObject



258
259
260
# File 'lib/mail/field.rb', line 258

def field_order_id
  @field_order_id ||= FIELD_ORDER_LOOKUP.fetch(self.name.to_s.downcase, 100)
end

#inspectObject



236
237
238
239
240
# File 'lib/mail/field.rb', line 236

def inspect
  "#<#{self.class.name} 0x#{(object_id * 2).to_s(16)} #{instance_variables.map do |ivar|
    "#{ivar}=#{instance_variable_get(ivar).inspect}"
  end.join(" ")}>"
end

#nameObject



220
221
222
# File 'lib/mail/field.rb', line 220

def name
  @name
end

#respond_to_missing?(method_name, include_private) ⇒ Boolean

Returns:

  • (Boolean)


266
267
268
# File 'lib/mail/field.rb', line 266

def respond_to_missing?(method_name, include_private)
  field.respond_to?(method_name, include_private) || super
end

#responsible_for?(field_name) ⇒ Boolean

Returns:

  • (Boolean)


250
251
252
# File 'lib/mail/field.rb', line 250

def responsible_for?(field_name)
  name.to_s.casecmp(field_name.to_s) == 0
end

#same(other) ⇒ Object



242
243
244
# File 'lib/mail/field.rb', line 242

def same(other)
  other.kind_of?(self.class) && Utilities.match_to_s(other.name, name)
end

#to_sObject



232
233
234
# File 'lib/mail/field.rb', line 232

def to_s
  field.to_s
end

#valueObject



224
225
226
# File 'lib/mail/field.rb', line 224

def value
  field.value
end

#value=(val) ⇒ Object



228
229
230
# File 'lib/mail/field.rb', line 228

def value=(val)
  @field = create_field(name, val, @charset)
end