mail 1.0.0

Sign up to get free protection for your applications and to get access to all the features.

Potentially problematic release.


This version of mail might be problematic. Click here for more details.

Files changed (107) hide show
  1. data/.gitignore +4 -0
  2. data/Manifest.txt +106 -0
  3. data/README.rdoc +441 -0
  4. data/Rakefile +38 -0
  5. data/lib/mail.rb +86 -0
  6. data/lib/mail/attachment.rb +90 -0
  7. data/lib/mail/body.rb +149 -0
  8. data/lib/mail/configuration.rb +90 -0
  9. data/lib/mail/core_extensions.rb +6 -0
  10. data/lib/mail/core_extensions/blank.rb +41 -0
  11. data/lib/mail/core_extensions/nil.rb +15 -0
  12. data/lib/mail/core_extensions/string.rb +31 -0
  13. data/lib/mail/elements/address.rb +293 -0
  14. data/lib/mail/elements/address_list.rb +62 -0
  15. data/lib/mail/elements/content_disposition_element.rb +34 -0
  16. data/lib/mail/elements/content_transfer_encoding_element.rb +21 -0
  17. data/lib/mail/elements/content_type_element.rb +39 -0
  18. data/lib/mail/elements/date_time_element.rb +26 -0
  19. data/lib/mail/elements/envelope_from_element.rb +34 -0
  20. data/lib/mail/elements/message_ids_element.rb +29 -0
  21. data/lib/mail/elements/mime_version_element.rb +26 -0
  22. data/lib/mail/elements/phrase_list.rb +21 -0
  23. data/lib/mail/elements/received_element.rb +30 -0
  24. data/lib/mail/encodings/base64.rb +17 -0
  25. data/lib/mail/encodings/encodings.rb +24 -0
  26. data/lib/mail/encodings/quoted_printable.rb +26 -0
  27. data/lib/mail/envelope.rb +35 -0
  28. data/lib/mail/field.rb +202 -0
  29. data/lib/mail/field_list.rb +33 -0
  30. data/lib/mail/fields/bcc_field.rb +40 -0
  31. data/lib/mail/fields/cc_field.rb +40 -0
  32. data/lib/mail/fields/comments_field.rb +41 -0
  33. data/lib/mail/fields/common/common_address.rb +62 -0
  34. data/lib/mail/fields/common/common_date.rb +35 -0
  35. data/lib/mail/fields/common/common_field.rb +128 -0
  36. data/lib/mail/fields/common/common_message_id.rb +35 -0
  37. data/lib/mail/fields/content_description_field.rb +15 -0
  38. data/lib/mail/fields/content_disposition_field.rb +34 -0
  39. data/lib/mail/fields/content_id_field.rb +50 -0
  40. data/lib/mail/fields/content_transfer_encoding_field.rb +28 -0
  41. data/lib/mail/fields/content_type_field.rb +50 -0
  42. data/lib/mail/fields/date_field.rb +44 -0
  43. data/lib/mail/fields/from_field.rb +40 -0
  44. data/lib/mail/fields/in_reply_to_field.rb +42 -0
  45. data/lib/mail/fields/keywords_field.rb +22 -0
  46. data/lib/mail/fields/message_id_field.rb +70 -0
  47. data/lib/mail/fields/mime_version_field.rb +42 -0
  48. data/lib/mail/fields/optional_field.rb +11 -0
  49. data/lib/mail/fields/received_field.rb +49 -0
  50. data/lib/mail/fields/references_field.rb +42 -0
  51. data/lib/mail/fields/reply_to_field.rb +40 -0
  52. data/lib/mail/fields/resent_bcc_field.rb +40 -0
  53. data/lib/mail/fields/resent_cc_field.rb +40 -0
  54. data/lib/mail/fields/resent_date_field.rb +16 -0
  55. data/lib/mail/fields/resent_from_field.rb +40 -0
  56. data/lib/mail/fields/resent_message_id_field.rb +20 -0
  57. data/lib/mail/fields/resent_sender_field.rb +48 -0
  58. data/lib/mail/fields/resent_to_field.rb +40 -0
  59. data/lib/mail/fields/return_path_field.rb +34 -0
  60. data/lib/mail/fields/sender_field.rb +48 -0
  61. data/lib/mail/fields/structured_field.rb +32 -0
  62. data/lib/mail/fields/subject_field.rb +14 -0
  63. data/lib/mail/fields/to_field.rb +40 -0
  64. data/lib/mail/fields/unstructured_field.rb +27 -0
  65. data/lib/mail/header.rb +213 -0
  66. data/lib/mail/mail.rb +120 -0
  67. data/lib/mail/message.rb +648 -0
  68. data/lib/mail/network/deliverable.rb +42 -0
  69. data/lib/mail/network/retrievable.rb +63 -0
  70. data/lib/mail/parsers/address_lists.rb +61 -0
  71. data/lib/mail/parsers/address_lists.treetop +19 -0
  72. data/lib/mail/parsers/content_disposition.rb +358 -0
  73. data/lib/mail/parsers/content_disposition.treetop +45 -0
  74. data/lib/mail/parsers/content_transfer_encoding.rb +179 -0
  75. data/lib/mail/parsers/content_transfer_encoding.treetop +25 -0
  76. data/lib/mail/parsers/content_type.rb +507 -0
  77. data/lib/mail/parsers/content_type.treetop +58 -0
  78. data/lib/mail/parsers/date_time.rb +111 -0
  79. data/lib/mail/parsers/date_time.treetop +11 -0
  80. data/lib/mail/parsers/envelope_from.rb +188 -0
  81. data/lib/mail/parsers/envelope_from.treetop +32 -0
  82. data/lib/mail/parsers/message_ids.rb +42 -0
  83. data/lib/mail/parsers/message_ids.treetop +15 -0
  84. data/lib/mail/parsers/mime_version.rb +141 -0
  85. data/lib/mail/parsers/mime_version.treetop +19 -0
  86. data/lib/mail/parsers/phrase_lists.rb +42 -0
  87. data/lib/mail/parsers/phrase_lists.treetop +15 -0
  88. data/lib/mail/parsers/received.rb +68 -0
  89. data/lib/mail/parsers/received.treetop +11 -0
  90. data/lib/mail/parsers/rfc2045.rb +406 -0
  91. data/lib/mail/parsers/rfc2045.treetop +35 -0
  92. data/lib/mail/parsers/rfc2822.rb +5005 -0
  93. data/lib/mail/parsers/rfc2822.treetop +402 -0
  94. data/lib/mail/parsers/rfc2822_obsolete.rb +3607 -0
  95. data/lib/mail/parsers/rfc2822_obsolete.treetop +241 -0
  96. data/lib/mail/part.rb +120 -0
  97. data/lib/mail/patterns.rb +42 -0
  98. data/lib/mail/utilities.rb +142 -0
  99. data/lib/mail/version.rb +10 -0
  100. data/lib/mail/version_specific/multibyte.rb +62 -0
  101. data/lib/mail/version_specific/multibyte/chars.rb +701 -0
  102. data/lib/mail/version_specific/multibyte/exceptions.rb +8 -0
  103. data/lib/mail/version_specific/multibyte/unicode_database.rb +71 -0
  104. data/lib/mail/version_specific/ruby_1_8.rb +61 -0
  105. data/lib/mail/version_specific/ruby_1_8_string.rb +88 -0
  106. data/lib/mail/version_specific/ruby_1_9.rb +49 -0
  107. metadata +192 -0
@@ -0,0 +1,33 @@
1
+ # encoding: utf-8
2
+ module Mail
3
+
4
+ # Field List class provides an enhanced array that keeps a list of
5
+ # email fields in order. And allows you to insert new fields without
6
+ # having to worry about the order they will appear in.
7
+ class FieldList < Array
8
+
9
+ include Enumerable
10
+
11
+ def <<( new_field )
12
+ current_entry = self.rindex(new_field.name)
13
+ if current_entry
14
+ self.insert((current_entry + 1), new_field)
15
+ else
16
+ insert_idx = -1
17
+ self.each_with_index do |item, idx|
18
+ case item <=> new_field
19
+ when -1
20
+ next
21
+ when 0
22
+ next
23
+ when 1
24
+ insert_idx = idx
25
+ break
26
+ end
27
+ end
28
+ insert(insert_idx, new_field)
29
+ end
30
+ end
31
+
32
+ end
33
+ end
@@ -0,0 +1,40 @@
1
+ # encoding: utf-8
2
+ #
3
+ # = Blind Carbon Copy Field
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 it's 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 #=> '#<Mail::Field:0x180e5e8 @field=#<Mail::BccField:0x180e1c4
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.to_s #=> 'Mikel Lindsaar <mikel@test.lindsaar.net>, ada@test.lindsaar.net'
25
+ # mail.bcc.addresses #=> ['mikel@test.lindsaar.net', 'ada@test.lindsaar.net']
26
+ # mail.bcc.formatted #=> ['Mikel Lindsaar <mikel@test.lindsaar.net>', 'ada@test.lindsaar.net']
27
+ #
28
+ module Mail
29
+ class BccField < StructuredField
30
+
31
+ include Mail::CommonAddress
32
+
33
+ FIELD_NAME = 'bcc'
34
+
35
+ def initialize(*args)
36
+ super(FIELD_NAME, strip_field(FIELD_NAME, args.last))
37
+ end
38
+
39
+ end
40
+ end
@@ -0,0 +1,40 @@
1
+ # encoding: utf-8
2
+ #
3
+ # = Carbon Copy Field
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 it's 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 #=> '#<Mail::Field:0x180e5e8 @field=#<Mail::CcField:0x180e1c4
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.to_s #=> 'Mikel Lindsaar <mikel@test.lindsaar.net>, ada@test.lindsaar.net'
25
+ # mail.cc.addresses #=> ['mikel@test.lindsaar.net', 'ada@test.lindsaar.net']
26
+ # mail.cc.formatted #=> ['Mikel Lindsaar <mikel@test.lindsaar.net>', 'ada@test.lindsaar.net']
27
+ #
28
+ module Mail
29
+ class CcField < StructuredField
30
+
31
+ include Mail::CommonAddress
32
+
33
+ FIELD_NAME = 'cc'
34
+
35
+ def initialize(*args)
36
+ super(FIELD_NAME, strip_field(FIELD_NAME, args.last))
37
+ end
38
+
39
+ end
40
+ end
@@ -0,0 +1,41 @@
1
+ # encoding: utf-8
2
+ #
3
+ # = Comments Field
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 it's 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 #=> '#<Mail::Field:0x180e5e8 @field=#<Mail::CommentsField:0x180e1c4
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.to_s #=> 'This is a comment'
24
+ #
25
+ # mail.comments = "This is another comment"
26
+ # mail.comments.map { |c| c.to_s }
27
+ # #=> ['This is a comment', "This is another comment"]
28
+ # mail.comments.to_s # Probably not what you want to do in this case
29
+ # #=> "This is a commentThis is another comment"
30
+ #
31
+ module Mail
32
+ class CommentsField < UnstructuredField
33
+
34
+ FIELD_NAME = 'comments'
35
+
36
+ def initialize(*args)
37
+ super(FIELD_NAME, strip_field(FIELD_NAME, args.last))
38
+ end
39
+
40
+ end
41
+ end
@@ -0,0 +1,62 @@
1
+ # encoding: utf-8
2
+ module Mail
3
+ module CommonAddress # :nodoc:
4
+
5
+ module ClassMethods # :nodoc:
6
+
7
+ end
8
+
9
+ module InstanceMethods # :doc:
10
+
11
+ # Allows you to iterate through each address object in the syntax tree
12
+ def each
13
+ tree.addresses.each do |address|
14
+ yield
15
+ end
16
+ end
17
+
18
+ # Returns the address string of all the addresses in the address list
19
+ def addresses
20
+ tree.addresses.map { |a| a.address }
21
+ end
22
+
23
+ # Returns the formatted string of all the addresses in the address list
24
+ def formatted
25
+ tree.addresses.map { |a| a.format }
26
+ end
27
+
28
+ # Returns a hash of group name => address strings for the address list
29
+ def groups
30
+ @groups = Hash.new
31
+ tree.group_recipients.each do |group|
32
+ @groups[group.group_name.text_value] = get_group_addresses(group.group_list.addresses)
33
+ end
34
+ @groups
35
+ end
36
+
37
+ # Returns the name of all the groups in a string
38
+ def group_names # :nodoc:
39
+ tree.group_names
40
+ end
41
+
42
+ private
43
+
44
+ # Returns the syntax tree of the Addresses
45
+ def tree # :nodoc:
46
+ @tree ||= AddressList.new(value)
47
+ end
48
+
49
+ def get_group_addresses(group_addresses)
50
+ group_addresses.map do |address_tree|
51
+ Mail::Address.new(address_tree)
52
+ end
53
+ end
54
+
55
+ end
56
+
57
+ def self.included(receiver) # :nodoc:
58
+ receiver.send :include, InstanceMethods
59
+ end
60
+
61
+ end
62
+ end
@@ -0,0 +1,35 @@
1
+ # encoding: utf-8
2
+ module Mail
3
+ module CommonDate # :nodoc:
4
+
5
+ module ClassMethods # :nodoc:
6
+
7
+ end
8
+
9
+ module InstanceMethods # :doc:
10
+
11
+ # Returns a date time object of the parsed date
12
+ def date_time
13
+ ::DateTime.parse("#{element.date_string} #{element.time_string}")
14
+ end
15
+
16
+ private
17
+
18
+ def element
19
+ @element ||= Mail::DateTimeElement.new(value)
20
+ end
21
+
22
+ # Returns the syntax tree of the Date
23
+ def tree
24
+ @tree ||= element.tree
25
+ end
26
+
27
+ end
28
+
29
+ def self.included(receiver) # :nodoc:
30
+ receiver.extend ClassMethods
31
+ receiver.send :include, InstanceMethods
32
+ end
33
+
34
+ end
35
+ end
@@ -0,0 +1,128 @@
1
+ # encoding: utf-8
2
+ module Mail
3
+ module CommonField # :nodoc:
4
+
5
+ module ClassMethods # :nodoc:
6
+
7
+ end
8
+
9
+ module InstanceMethods # :doc:
10
+
11
+ def name=(value)
12
+ @name = capitalize_field(value)
13
+ end
14
+
15
+ def name
16
+ @name
17
+ end
18
+
19
+ def value=(value)
20
+ @length = nil
21
+ @tree = nil
22
+ @element = nil
23
+ @value = value
24
+ end
25
+
26
+ def value
27
+ @value
28
+ end
29
+
30
+ def encoded
31
+ value.blank? ? nil : "#{wrapped_value}\r\n"
32
+ end
33
+
34
+ def decoded
35
+ value.blank? ? nil : "#{name}: #{value}\r\n"
36
+ end
37
+
38
+ def to_s
39
+ decoded.to_s
40
+ end
41
+
42
+ def field_length
43
+ @length ||= name.length + value.length + ': '.length
44
+ end
45
+
46
+ def responsible_for?( val )
47
+ name.to_s.downcase == val.to_s.downcase
48
+ end
49
+
50
+ private
51
+
52
+ def strip_field(field_name, string)
53
+ string.to_s.gsub(/#{field_name}:\s+/i, '')
54
+ end
55
+
56
+
57
+ # 2.2.3. Long Header Fields
58
+ #
59
+ # Each header field is logically a single line of characters comprising
60
+ # the field name, the colon, and the field body. For convenience
61
+ # however, and to deal with the 998/78 character limitations per line,
62
+ # the field body portion of a header field can be split into a multiple
63
+ # line representation; this is called "folding". The general rule is
64
+ # that wherever this standard allows for folding white space (not
65
+ # simply WSP characters), a CRLF may be inserted before any WSP. For
66
+ # example, the header field:
67
+ #
68
+ # Subject: This is a test
69
+ #
70
+ # can be represented as:
71
+ #
72
+ # Subject: This
73
+ # is a test
74
+ #
75
+ # Note: Though structured field bodies are defined in such a way that
76
+ # folding can take place between many of the lexical tokens (and even
77
+ # within some of the lexical tokens), folding SHOULD be limited to
78
+ # placing the CRLF at higher-level syntactic breaks. For instance, if
79
+ # a field body is defined as comma-separated values, it is recommended
80
+ # that folding occur after the comma separating the structured items in
81
+ # preference to other places where the field could be folded, even if
82
+ # it is allowed elsewhere.
83
+ def wrapped_value # :nodoc:
84
+ case
85
+ when decoded.ascii_only? && field_length <= 78
86
+ "#{name}: #{value}"
87
+ when field_length <= 40 # Allow for =?ISO-8859-1?B?=...=
88
+ "#{name}: #{encode(value)}"
89
+ else
90
+ @folded_line = []
91
+ @unfolded_line = value.clone
92
+ fold("#{name}: ".length)
93
+ folded = @folded_line.compact.join("\r\n\t")
94
+ "#{name}: #{folded}"
95
+ end
96
+ end
97
+
98
+ def fold(prepend = 0) # :nodoc:
99
+ # Get the last whitespace character, OR we'll just choose
100
+ # 78 if there is no whitespace
101
+ @unfolded_line.ascii_only? ? (limit = 78 - prepend) : (limit = 40 - prepend)
102
+ wspp = @unfolded_line.slice(0..limit) =~ /[ \t][^ \T]*$/ || limit
103
+ wspp = limit if wspp == 0
104
+ @folded_line << encode(@unfolded_line.slice!(0...wspp))
105
+ if @unfolded_line.length > limit
106
+ fold
107
+ else
108
+ @folded_line << encode(@unfolded_line)
109
+ end
110
+ end
111
+
112
+ def encode(value)
113
+ if RUBY_VERSION < '1.9'
114
+ Encodings.b_encode(value, $KCODE)
115
+ else
116
+ Encodings.b_encode(value, @value.encoding)
117
+ end
118
+ end
119
+
120
+ end
121
+
122
+ def self.included(receiver) # :nodoc:
123
+ receiver.extend ClassMethods
124
+ receiver.send :include, InstanceMethods
125
+ end
126
+
127
+ end
128
+ end
@@ -0,0 +1,35 @@
1
+ # encoding: utf-8
2
+ module Mail
3
+ module CommonMessageId # :nodoc:
4
+
5
+ module ClassMethods # :nodoc:
6
+
7
+ end
8
+
9
+ module InstanceMethods # :doc:
10
+
11
+ def tree
12
+ @tree ||= element.tree
13
+ end
14
+
15
+ def element
16
+ @element ||= Mail::MessageIdsElement.new(value)
17
+ end
18
+
19
+ def message_id
20
+ element.message_id
21
+ end
22
+
23
+ def message_ids
24
+ element.message_ids
25
+ end
26
+
27
+ end
28
+
29
+ def self.included(receiver) # :nodoc:
30
+ receiver.extend ClassMethods
31
+ receiver.send :include, InstanceMethods
32
+ end
33
+
34
+ end
35
+ end
@@ -0,0 +1,15 @@
1
+ # encoding: utf-8
2
+ #
3
+ #
4
+ #
5
+ module Mail
6
+ class ContentDescriptionField < UnstructuredField
7
+
8
+ FIELD_NAME = 'content-description'
9
+
10
+ def initialize(*args)
11
+ super(FIELD_NAME, strip_field(FIELD_NAME, args.last))
12
+ end
13
+
14
+ end
15
+ end
@@ -0,0 +1,34 @@
1
+ # encoding: utf-8
2
+ #
3
+ #
4
+ #
5
+ module Mail
6
+ class ContentDispositionField < StructuredField
7
+
8
+ FIELD_NAME = 'content-disposition'
9
+
10
+ def initialize(*args)
11
+ super(FIELD_NAME, strip_field(FIELD_NAME, args.last))
12
+ end
13
+
14
+ def tree
15
+ @element ||= Mail::ContentDispositionElement.new(value)
16
+ @tree ||= @element.tree
17
+ end
18
+
19
+ def element
20
+ @element ||= Mail::ContentDispositionElement.new(value)
21
+ end
22
+
23
+ def disposition_type
24
+ element.disposition_type
25
+ end
26
+
27
+ def parameters
28
+ @parameters = Hash.new
29
+ element.parameters.each { |p| @parameters.merge!(p) }
30
+ @parameters
31
+ end
32
+
33
+ end
34
+ end