mail-portertech 2.6.2.edge
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 +7 -0
- data/CHANGELOG.rdoc +753 -0
- data/CONTRIBUTING.md +60 -0
- data/Dependencies.txt +2 -0
- data/Gemfile +15 -0
- data/MIT-LICENSE +20 -0
- data/README.md +683 -0
- data/Rakefile +29 -0
- data/TODO.rdoc +9 -0
- data/lib/mail.rb +91 -0
- data/lib/mail/attachments_list.rb +104 -0
- data/lib/mail/body.rb +291 -0
- data/lib/mail/check_delivery_params.rb +20 -0
- data/lib/mail/configuration.rb +75 -0
- data/lib/mail/core_extensions/nil.rb +19 -0
- data/lib/mail/core_extensions/object.rb +13 -0
- data/lib/mail/core_extensions/smtp.rb +24 -0
- data/lib/mail/core_extensions/string.rb +43 -0
- data/lib/mail/core_extensions/string/access.rb +145 -0
- data/lib/mail/core_extensions/string/multibyte.rb +78 -0
- data/lib/mail/elements.rb +14 -0
- data/lib/mail/elements/address.rb +270 -0
- data/lib/mail/elements/address_list.rb +51 -0
- data/lib/mail/elements/content_disposition_element.rb +26 -0
- data/lib/mail/elements/content_location_element.rb +21 -0
- data/lib/mail/elements/content_transfer_encoding_element.rb +17 -0
- data/lib/mail/elements/content_type_element.rb +31 -0
- data/lib/mail/elements/date_time_element.rb +22 -0
- data/lib/mail/elements/envelope_from_element.rb +39 -0
- data/lib/mail/elements/message_ids_element.rb +24 -0
- data/lib/mail/elements/mime_version_element.rb +22 -0
- data/lib/mail/elements/phrase_list.rb +16 -0
- data/lib/mail/elements/received_element.rb +26 -0
- data/lib/mail/encodings.rb +304 -0
- data/lib/mail/encodings/7bit.rb +31 -0
- data/lib/mail/encodings/8bit.rb +31 -0
- data/lib/mail/encodings/base64.rb +33 -0
- data/lib/mail/encodings/binary.rb +31 -0
- data/lib/mail/encodings/quoted_printable.rb +39 -0
- data/lib/mail/encodings/transfer_encoding.rb +58 -0
- data/lib/mail/envelope.rb +30 -0
- data/lib/mail/field.rb +247 -0
- data/lib/mail/field_list.rb +33 -0
- data/lib/mail/fields.rb +35 -0
- data/lib/mail/fields/bcc_field.rb +56 -0
- data/lib/mail/fields/cc_field.rb +55 -0
- data/lib/mail/fields/comments_field.rb +41 -0
- data/lib/mail/fields/common/address_container.rb +16 -0
- data/lib/mail/fields/common/common_address.rb +135 -0
- data/lib/mail/fields/common/common_date.rb +35 -0
- data/lib/mail/fields/common/common_field.rb +57 -0
- data/lib/mail/fields/common/common_message_id.rb +48 -0
- data/lib/mail/fields/common/parameter_hash.rb +58 -0
- data/lib/mail/fields/content_description_field.rb +19 -0
- data/lib/mail/fields/content_disposition_field.rb +70 -0
- data/lib/mail/fields/content_id_field.rb +62 -0
- data/lib/mail/fields/content_location_field.rb +42 -0
- data/lib/mail/fields/content_transfer_encoding_field.rb +44 -0
- data/lib/mail/fields/content_type_field.rb +201 -0
- data/lib/mail/fields/date_field.rb +57 -0
- data/lib/mail/fields/from_field.rb +55 -0
- data/lib/mail/fields/in_reply_to_field.rb +56 -0
- data/lib/mail/fields/keywords_field.rb +44 -0
- data/lib/mail/fields/message_id_field.rb +82 -0
- data/lib/mail/fields/mime_version_field.rb +53 -0
- data/lib/mail/fields/optional_field.rb +13 -0
- data/lib/mail/fields/received_field.rb +75 -0
- data/lib/mail/fields/references_field.rb +56 -0
- data/lib/mail/fields/reply_to_field.rb +55 -0
- data/lib/mail/fields/resent_bcc_field.rb +55 -0
- data/lib/mail/fields/resent_cc_field.rb +55 -0
- data/lib/mail/fields/resent_date_field.rb +35 -0
- data/lib/mail/fields/resent_from_field.rb +55 -0
- data/lib/mail/fields/resent_message_id_field.rb +34 -0
- data/lib/mail/fields/resent_sender_field.rb +62 -0
- data/lib/mail/fields/resent_to_field.rb +55 -0
- data/lib/mail/fields/return_path_field.rb +65 -0
- data/lib/mail/fields/sender_field.rb +67 -0
- data/lib/mail/fields/structured_field.rb +51 -0
- data/lib/mail/fields/subject_field.rb +16 -0
- data/lib/mail/fields/to_field.rb +55 -0
- data/lib/mail/fields/unstructured_field.rb +204 -0
- data/lib/mail/header.rb +274 -0
- data/lib/mail/indifferent_hash.rb +146 -0
- data/lib/mail/mail.rb +267 -0
- data/lib/mail/matchers/has_sent_mail.rb +157 -0
- data/lib/mail/message.rb +2160 -0
- data/lib/mail/multibyte.rb +42 -0
- data/lib/mail/multibyte/chars.rb +474 -0
- data/lib/mail/multibyte/exceptions.rb +8 -0
- data/lib/mail/multibyte/unicode.rb +400 -0
- data/lib/mail/multibyte/utils.rb +60 -0
- data/lib/mail/network.rb +14 -0
- data/lib/mail/network/delivery_methods/exim.rb +52 -0
- data/lib/mail/network/delivery_methods/file_delivery.rb +45 -0
- data/lib/mail/network/delivery_methods/sendmail.rb +89 -0
- data/lib/mail/network/delivery_methods/smtp.rb +142 -0
- data/lib/mail/network/delivery_methods/smtp_connection.rb +61 -0
- data/lib/mail/network/delivery_methods/test_mailer.rb +44 -0
- data/lib/mail/network/retriever_methods/base.rb +63 -0
- data/lib/mail/network/retriever_methods/imap.rb +173 -0
- data/lib/mail/network/retriever_methods/pop3.rb +140 -0
- data/lib/mail/network/retriever_methods/test_retriever.rb +43 -0
- data/lib/mail/parsers.rb +26 -0
- data/lib/mail/parsers/address_lists_parser.rb +132 -0
- data/lib/mail/parsers/content_disposition_parser.rb +67 -0
- data/lib/mail/parsers/content_location_parser.rb +35 -0
- data/lib/mail/parsers/content_transfer_encoding_parser.rb +33 -0
- data/lib/mail/parsers/content_type_parser.rb +64 -0
- data/lib/mail/parsers/date_time_parser.rb +36 -0
- data/lib/mail/parsers/envelope_from_parser.rb +45 -0
- data/lib/mail/parsers/message_ids_parser.rb +39 -0
- data/lib/mail/parsers/mime_version_parser.rb +41 -0
- data/lib/mail/parsers/phrase_lists_parser.rb +33 -0
- data/lib/mail/parsers/ragel.rb +17 -0
- data/lib/mail/parsers/ragel/common.rl +184 -0
- data/lib/mail/parsers/ragel/date_time.rl +30 -0
- data/lib/mail/parsers/ragel/parser_info.rb +61 -0
- data/lib/mail/parsers/ragel/ruby.rb +39 -0
- data/lib/mail/parsers/ragel/ruby/machines/address_lists_machine.rb +14864 -0
- data/lib/mail/parsers/ragel/ruby/machines/address_lists_machine.rb.rl +37 -0
- data/lib/mail/parsers/ragel/ruby/machines/content_disposition_machine.rb +751 -0
- data/lib/mail/parsers/ragel/ruby/machines/content_disposition_machine.rb.rl +37 -0
- data/lib/mail/parsers/ragel/ruby/machines/content_location_machine.rb +614 -0
- data/lib/mail/parsers/ragel/ruby/machines/content_location_machine.rb.rl +37 -0
- data/lib/mail/parsers/ragel/ruby/machines/content_transfer_encoding_machine.rb +447 -0
- data/lib/mail/parsers/ragel/ruby/machines/content_transfer_encoding_machine.rb.rl +37 -0
- data/lib/mail/parsers/ragel/ruby/machines/content_type_machine.rb +825 -0
- data/lib/mail/parsers/ragel/ruby/machines/content_type_machine.rb.rl +37 -0
- data/lib/mail/parsers/ragel/ruby/machines/date_time_machine.rb +817 -0
- data/lib/mail/parsers/ragel/ruby/machines/date_time_machine.rb.rl +37 -0
- data/lib/mail/parsers/ragel/ruby/machines/envelope_from_machine.rb +2129 -0
- data/lib/mail/parsers/ragel/ruby/machines/envelope_from_machine.rb.rl +37 -0
- data/lib/mail/parsers/ragel/ruby/machines/message_ids_machine.rb +1570 -0
- data/lib/mail/parsers/ragel/ruby/machines/message_ids_machine.rb.rl +37 -0
- data/lib/mail/parsers/ragel/ruby/machines/mime_version_machine.rb +440 -0
- data/lib/mail/parsers/ragel/ruby/machines/mime_version_machine.rb.rl +37 -0
- data/lib/mail/parsers/ragel/ruby/machines/phrase_lists_machine.rb +564 -0
- data/lib/mail/parsers/ragel/ruby/machines/phrase_lists_machine.rb.rl +37 -0
- data/lib/mail/parsers/ragel/ruby/machines/rb_actions.rl +51 -0
- data/lib/mail/parsers/ragel/ruby/machines/received_machine.rb +5144 -0
- data/lib/mail/parsers/ragel/ruby/machines/received_machine.rb.rl +37 -0
- data/lib/mail/parsers/ragel/ruby/parser.rb.rl.erb +37 -0
- data/lib/mail/parsers/received_parser.rb +47 -0
- data/lib/mail/part.rb +120 -0
- data/lib/mail/parts_list.rb +57 -0
- data/lib/mail/patterns.rb +37 -0
- data/lib/mail/utilities.rb +225 -0
- data/lib/mail/values/unicode_tables.dat +0 -0
- data/lib/mail/version.rb +4 -0
- data/lib/mail/version_specific/ruby_1_8.rb +119 -0
- data/lib/mail/version_specific/ruby_1_9.rb +159 -0
- metadata +276 -0
data/Rakefile
ADDED
@@ -0,0 +1,29 @@
|
|
1
|
+
if !ENV["APPRAISAL_INITIALIZED"] && !ENV["TRAVIS"]
|
2
|
+
ENV['BUNDLE_GEMFILE'] ||= File.expand_path('../Gemfile', __FILE__)
|
3
|
+
end
|
4
|
+
require 'rubygems'
|
5
|
+
require 'bundler/setup'
|
6
|
+
|
7
|
+
require 'rake/testtask'
|
8
|
+
require 'rspec/core/rake_task'
|
9
|
+
|
10
|
+
desc "Build a gem file"
|
11
|
+
task :build do
|
12
|
+
system "gem build mail.gemspec"
|
13
|
+
end
|
14
|
+
|
15
|
+
task :default => :spec
|
16
|
+
|
17
|
+
RSpec::Core::RakeTask.new(:spec) do |t|
|
18
|
+
t.ruby_opts = '-w'
|
19
|
+
t.rspec_opts = %w(--backtrace --color)
|
20
|
+
end
|
21
|
+
|
22
|
+
begin
|
23
|
+
require "appraisal"
|
24
|
+
rescue LoadError
|
25
|
+
warn "Appraisal is only available in test/development"
|
26
|
+
end
|
27
|
+
|
28
|
+
# load custom rake tasks
|
29
|
+
Dir["#{File.dirname(__FILE__)}/tasks/**/*.rake"].sort.each { |ext| load ext }
|
data/TODO.rdoc
ADDED
@@ -0,0 +1,9 @@
|
|
1
|
+
== Not really in any order:
|
2
|
+
|
3
|
+
* Add multibyte handling to fields, if they get a multibyte string, try encoding it into
|
4
|
+
UTF-8 B first, if this fails, throw an error.
|
5
|
+
|
6
|
+
* Cleanup the treetop parsers......... do I _really_ need that many entrance files?
|
7
|
+
|
8
|
+
* Simplify the relationship of Headers and Fields. Doing too much of the Field work
|
9
|
+
in the Header class on instantiating fields. Header should just say "Field, do it!"
|
data/lib/mail.rb
ADDED
@@ -0,0 +1,91 @@
|
|
1
|
+
# encoding: utf-8
|
2
|
+
module Mail # :doc:
|
3
|
+
|
4
|
+
require 'date'
|
5
|
+
require 'shellwords'
|
6
|
+
|
7
|
+
require 'uri'
|
8
|
+
require 'net/smtp'
|
9
|
+
require 'mime/types'
|
10
|
+
|
11
|
+
if RUBY_VERSION <= '1.8.6'
|
12
|
+
begin
|
13
|
+
require 'tlsmail'
|
14
|
+
rescue LoadError
|
15
|
+
raise "You need to install tlsmail if you are using ruby <= 1.8.6"
|
16
|
+
end
|
17
|
+
end
|
18
|
+
|
19
|
+
if RUBY_VERSION >= "1.9.0"
|
20
|
+
require 'mail/version_specific/ruby_1_9'
|
21
|
+
RubyVer = Ruby19
|
22
|
+
else
|
23
|
+
require 'mail/version_specific/ruby_1_8'
|
24
|
+
RubyVer = Ruby18
|
25
|
+
end
|
26
|
+
|
27
|
+
require 'mail/version'
|
28
|
+
|
29
|
+
require 'mail/core_extensions/nil'
|
30
|
+
require 'mail/core_extensions/object'
|
31
|
+
require 'mail/core_extensions/string'
|
32
|
+
require 'mail/core_extensions/smtp' if RUBY_VERSION < '1.9.3'
|
33
|
+
require 'mail/indifferent_hash'
|
34
|
+
|
35
|
+
# Only load our multibyte extensions if AS is not already loaded
|
36
|
+
if defined?(ActiveSupport)
|
37
|
+
require 'active_support/inflector'
|
38
|
+
else
|
39
|
+
require 'mail/core_extensions/string/access'
|
40
|
+
require 'mail/core_extensions/string/multibyte'
|
41
|
+
require 'mail/multibyte'
|
42
|
+
end
|
43
|
+
|
44
|
+
require 'mail/patterns'
|
45
|
+
require 'mail/utilities'
|
46
|
+
require 'mail/configuration'
|
47
|
+
|
48
|
+
@@autoloads = {}
|
49
|
+
def self.register_autoload(name, path)
|
50
|
+
@@autoloads[name] = path
|
51
|
+
autoload(name, path)
|
52
|
+
end
|
53
|
+
|
54
|
+
# This runs through the autoload list and explictly requires them for you.
|
55
|
+
# Useful when running mail in a threaded process.
|
56
|
+
#
|
57
|
+
# Usage:
|
58
|
+
#
|
59
|
+
# require 'mail'
|
60
|
+
# Mail.eager_autoload!
|
61
|
+
def self.eager_autoload!
|
62
|
+
@@autoloads.each { |_,path| require(path) }
|
63
|
+
end
|
64
|
+
|
65
|
+
# Autoload mail send and receive classes.
|
66
|
+
require 'mail/network'
|
67
|
+
|
68
|
+
require 'mail/message'
|
69
|
+
require 'mail/part'
|
70
|
+
require 'mail/header'
|
71
|
+
require 'mail/parts_list'
|
72
|
+
require 'mail/attachments_list'
|
73
|
+
require 'mail/body'
|
74
|
+
require 'mail/field'
|
75
|
+
require 'mail/field_list'
|
76
|
+
|
77
|
+
require 'mail/envelope'
|
78
|
+
|
79
|
+
require 'mail/parsers'
|
80
|
+
|
81
|
+
# Autoload header field elements and transfer encodings.
|
82
|
+
require 'mail/elements'
|
83
|
+
require 'mail/encodings'
|
84
|
+
require 'mail/encodings/base64'
|
85
|
+
require 'mail/encodings/quoted_printable'
|
86
|
+
|
87
|
+
require 'mail/matchers/has_sent_mail'
|
88
|
+
|
89
|
+
# Finally... require all the Mail.methods
|
90
|
+
require 'mail/mail'
|
91
|
+
end
|
@@ -0,0 +1,104 @@
|
|
1
|
+
module Mail
|
2
|
+
class AttachmentsList < Array
|
3
|
+
|
4
|
+
def initialize(parts_list)
|
5
|
+
@parts_list = parts_list
|
6
|
+
@content_disposition_type = 'attachment'
|
7
|
+
parts_list.map { |p|
|
8
|
+
if p.content_type == "message/rfc822"
|
9
|
+
Mail.new(p.body).attachments
|
10
|
+
elsif p.parts.empty?
|
11
|
+
p if p.attachment?
|
12
|
+
else
|
13
|
+
p.attachments
|
14
|
+
end
|
15
|
+
}.flatten.compact.each { |a| self << a }
|
16
|
+
self
|
17
|
+
end
|
18
|
+
|
19
|
+
def inline
|
20
|
+
@content_disposition_type = 'inline'
|
21
|
+
self
|
22
|
+
end
|
23
|
+
|
24
|
+
# Returns the attachment by filename or at index.
|
25
|
+
#
|
26
|
+
# mail.attachments['test.png'] = File.read('test.png')
|
27
|
+
# mail.attachments['test.jpg'] = File.read('test.jpg')
|
28
|
+
#
|
29
|
+
# mail.attachments['test.png'].filename #=> 'test.png'
|
30
|
+
# mail.attachments[1].filename #=> 'test.jpg'
|
31
|
+
def [](index_value)
|
32
|
+
if index_value.is_a?(Fixnum)
|
33
|
+
self.fetch(index_value)
|
34
|
+
else
|
35
|
+
self.select { |a| a.filename == index_value }.first
|
36
|
+
end
|
37
|
+
end
|
38
|
+
|
39
|
+
def []=(name, value)
|
40
|
+
encoded_name = Mail::Encodings.decode_encode name, :encode
|
41
|
+
default_values = { :content_type => "#{set_mime_type(name)}; filename=\"#{encoded_name}\"",
|
42
|
+
:content_transfer_encoding => "#{guess_encoding}",
|
43
|
+
:content_disposition => "#{@content_disposition_type}; filename=\"#{encoded_name}\"" }
|
44
|
+
|
45
|
+
if value.is_a?(Hash)
|
46
|
+
|
47
|
+
default_values[:body] = value.delete(:content) if value[:content]
|
48
|
+
|
49
|
+
default_values[:body] = value.delete(:data) if value[:data]
|
50
|
+
|
51
|
+
encoding = value.delete(:transfer_encoding) || value.delete(:encoding)
|
52
|
+
if encoding
|
53
|
+
if Mail::Encodings.defined? encoding
|
54
|
+
default_values[:content_transfer_encoding] = encoding
|
55
|
+
else
|
56
|
+
raise "Do not know how to handle Content Transfer Encoding #{encoding}, please choose either quoted-printable or base64"
|
57
|
+
end
|
58
|
+
end
|
59
|
+
|
60
|
+
if value[:mime_type]
|
61
|
+
default_values[:content_type] = value.delete(:mime_type)
|
62
|
+
@mime_type = MIME::Types[default_values[:content_type]].first
|
63
|
+
default_values[:content_transfer_encoding] ||= guess_encoding
|
64
|
+
end
|
65
|
+
|
66
|
+
hash = default_values.merge(value)
|
67
|
+
else
|
68
|
+
default_values[:body] = value
|
69
|
+
hash = default_values
|
70
|
+
end
|
71
|
+
|
72
|
+
if hash[:body].respond_to? :force_encoding and hash[:body].respond_to? :valid_encoding?
|
73
|
+
if not hash[:body].valid_encoding? and default_values[:content_transfer_encoding].downcase == "binary"
|
74
|
+
hash[:body].force_encoding("BINARY")
|
75
|
+
end
|
76
|
+
end
|
77
|
+
|
78
|
+
attachment = Part.new(hash)
|
79
|
+
attachment.add_content_id(hash[:content_id])
|
80
|
+
|
81
|
+
@parts_list << attachment
|
82
|
+
end
|
83
|
+
|
84
|
+
# Uses the mime type to try and guess the encoding, if it is a binary type, or unknown, then we
|
85
|
+
# set it to binary, otherwise as set to plain text
|
86
|
+
def guess_encoding
|
87
|
+
if @mime_type && !@mime_type.binary?
|
88
|
+
"7bit"
|
89
|
+
else
|
90
|
+
"binary"
|
91
|
+
end
|
92
|
+
end
|
93
|
+
|
94
|
+
def set_mime_type(filename)
|
95
|
+
# Have to do this because MIME::Types is not Ruby 1.9 safe yet
|
96
|
+
if RUBY_VERSION >= '1.9'
|
97
|
+
filename = filename.encode(Encoding::UTF_8) if filename.respond_to?(:encode)
|
98
|
+
end
|
99
|
+
|
100
|
+
@mime_type = MIME::Types.type_for(filename).first
|
101
|
+
end
|
102
|
+
|
103
|
+
end
|
104
|
+
end
|
data/lib/mail/body.rb
ADDED
@@ -0,0 +1,291 @@
|
|
1
|
+
# encoding: utf-8
|
2
|
+
module Mail
|
3
|
+
|
4
|
+
# = Body
|
5
|
+
#
|
6
|
+
# The body is where the text of the email is stored. Mail treats the body
|
7
|
+
# as a single object. The body itself has no information about boundaries
|
8
|
+
# used in the MIME standard, it just looks at its content as either a single
|
9
|
+
# block of text, or (if it is a multipart message) as an array of blocks of text.
|
10
|
+
#
|
11
|
+
# A body has to be told to split itself up into a multipart message by calling
|
12
|
+
# #split with the correct boundary. This is because the body object has no way
|
13
|
+
# of knowing what the correct boundary is for itself (there could be many
|
14
|
+
# boundaries in a body in the case of a nested MIME text).
|
15
|
+
#
|
16
|
+
# Once split is called, Mail::Body will slice itself up on this boundary,
|
17
|
+
# assigning anything that appears before the first part to the preamble, and
|
18
|
+
# anything that appears after the closing boundary to the epilogue, then
|
19
|
+
# each part gets initialized into a Mail::Part object.
|
20
|
+
#
|
21
|
+
# The boundary that is used to split up the Body is also stored in the Body
|
22
|
+
# object for use on encoding itself back out to a string. You can
|
23
|
+
# overwrite this if it needs to be changed.
|
24
|
+
#
|
25
|
+
# On encoding, the body will return the preamble, then each part joined by
|
26
|
+
# the boundary, followed by a closing boundary string and then the epilogue.
|
27
|
+
class Body
|
28
|
+
|
29
|
+
def initialize(string = '')
|
30
|
+
@boundary = nil
|
31
|
+
@preamble = nil
|
32
|
+
@epilogue = nil
|
33
|
+
@charset = nil
|
34
|
+
@part_sort_order = [ "text/plain", "text/enriched", "text/html" ]
|
35
|
+
@parts = Mail::PartsList.new
|
36
|
+
if string.blank?
|
37
|
+
@raw_source = ''
|
38
|
+
else
|
39
|
+
# Do join first incase we have been given an Array in Ruby 1.9
|
40
|
+
if string.respond_to?(:join)
|
41
|
+
@raw_source = string.join('')
|
42
|
+
elsif string.respond_to?(:to_s)
|
43
|
+
@raw_source = string.to_s
|
44
|
+
else
|
45
|
+
raise "You can only assign a string or an object that responds_to? :join or :to_s to a body."
|
46
|
+
end
|
47
|
+
end
|
48
|
+
@encoding = (only_us_ascii? ? '7bit' : '8bit')
|
49
|
+
set_charset
|
50
|
+
end
|
51
|
+
|
52
|
+
# Matches this body with another body. Also matches the decoded value of this
|
53
|
+
# body with a string.
|
54
|
+
#
|
55
|
+
# Examples:
|
56
|
+
#
|
57
|
+
# body = Mail::Body.new('The body')
|
58
|
+
# body == body #=> true
|
59
|
+
#
|
60
|
+
# body = Mail::Body.new('The body')
|
61
|
+
# body == 'The body' #=> true
|
62
|
+
#
|
63
|
+
# body = Mail::Body.new("VGhlIGJvZHk=\n")
|
64
|
+
# body.encoding = 'base64'
|
65
|
+
# body == "The body" #=> true
|
66
|
+
def ==(other)
|
67
|
+
if other.class == String
|
68
|
+
self.decoded == other
|
69
|
+
else
|
70
|
+
super
|
71
|
+
end
|
72
|
+
end
|
73
|
+
|
74
|
+
# Accepts a string and performs a regular expression against the decoded text
|
75
|
+
#
|
76
|
+
# Examples:
|
77
|
+
#
|
78
|
+
# body = Mail::Body.new('The body')
|
79
|
+
# body =~ /The/ #=> 0
|
80
|
+
#
|
81
|
+
# body = Mail::Body.new("VGhlIGJvZHk=\n")
|
82
|
+
# body.encoding = 'base64'
|
83
|
+
# body =~ /The/ #=> 0
|
84
|
+
def =~(regexp)
|
85
|
+
self.decoded =~ regexp
|
86
|
+
end
|
87
|
+
|
88
|
+
# Accepts a string and performs a regular expression against the decoded text
|
89
|
+
#
|
90
|
+
# Examples:
|
91
|
+
#
|
92
|
+
# body = Mail::Body.new('The body')
|
93
|
+
# body.match(/The/) #=> #<MatchData "The">
|
94
|
+
#
|
95
|
+
# body = Mail::Body.new("VGhlIGJvZHk=\n")
|
96
|
+
# body.encoding = 'base64'
|
97
|
+
# body.match(/The/) #=> #<MatchData "The">
|
98
|
+
def match(regexp)
|
99
|
+
self.decoded.match(regexp)
|
100
|
+
end
|
101
|
+
|
102
|
+
# Accepts anything that responds to #to_s and checks if it's a substring of the decoded text
|
103
|
+
#
|
104
|
+
# Examples:
|
105
|
+
#
|
106
|
+
# body = Mail::Body.new('The body')
|
107
|
+
# body.include?('The') #=> true
|
108
|
+
#
|
109
|
+
# body = Mail::Body.new("VGhlIGJvZHk=\n")
|
110
|
+
# body.encoding = 'base64'
|
111
|
+
# body.include?('The') #=> true
|
112
|
+
def include?(other)
|
113
|
+
self.decoded.include?(other.to_s)
|
114
|
+
end
|
115
|
+
|
116
|
+
# Allows you to set the sort order of the parts, overriding the default sort order.
|
117
|
+
# Defaults to 'text/plain', then 'text/enriched', then 'text/html' with any other content
|
118
|
+
# type coming after.
|
119
|
+
def set_sort_order(order)
|
120
|
+
@part_sort_order = order
|
121
|
+
end
|
122
|
+
|
123
|
+
# Allows you to sort the parts according to the default sort order, or the sort order you
|
124
|
+
# set with :set_sort_order.
|
125
|
+
#
|
126
|
+
# sort_parts! is also called from :encode, so there is no need for you to call this explicitly
|
127
|
+
def sort_parts!
|
128
|
+
@parts.each do |p|
|
129
|
+
p.body.set_sort_order(@part_sort_order)
|
130
|
+
p.body.sort_parts!
|
131
|
+
end
|
132
|
+
@parts.sort!(@part_sort_order)
|
133
|
+
end
|
134
|
+
|
135
|
+
# Returns the raw source that the body was initialized with, without
|
136
|
+
# any tampering
|
137
|
+
def raw_source
|
138
|
+
@raw_source
|
139
|
+
end
|
140
|
+
|
141
|
+
def get_best_encoding(target)
|
142
|
+
target_encoding = Mail::Encodings.get_encoding(target)
|
143
|
+
target_encoding.get_best_compatible(encoding, raw_source)
|
144
|
+
end
|
145
|
+
|
146
|
+
# Returns a body encoded using transfer_encoding. Multipart always uses an
|
147
|
+
# identiy encoding (i.e. no encoding).
|
148
|
+
# Calling this directly is not a good idea, but supported for compatibility
|
149
|
+
# TODO: Validate that preamble and epilogue are valid for requested encoding
|
150
|
+
def encoded(transfer_encoding = '8bit')
|
151
|
+
if multipart?
|
152
|
+
self.sort_parts!
|
153
|
+
encoded_parts = parts.map { |p| p.encoded }
|
154
|
+
([preamble] + encoded_parts).join(crlf_boundary) + end_boundary + epilogue.to_s
|
155
|
+
else
|
156
|
+
be = get_best_encoding(transfer_encoding)
|
157
|
+
dec = Mail::Encodings::get_encoding(encoding)
|
158
|
+
enc = Mail::Encodings::get_encoding(be)
|
159
|
+
if transfer_encoding == encoding and dec.nil?
|
160
|
+
# Cannot decode, so skip normalization
|
161
|
+
raw_source
|
162
|
+
else
|
163
|
+
# Decode then encode to normalize and allow transforming
|
164
|
+
# from base64 to Q-P and vice versa
|
165
|
+
decoded = dec.decode(raw_source)
|
166
|
+
if defined?(Encoding) && charset && charset != "US-ASCII"
|
167
|
+
decoded.encode!(charset)
|
168
|
+
decoded.force_encoding('BINARY') unless Encoding.find(charset).ascii_compatible?
|
169
|
+
end
|
170
|
+
enc.encode(decoded)
|
171
|
+
end
|
172
|
+
end
|
173
|
+
end
|
174
|
+
|
175
|
+
def decoded
|
176
|
+
if !Encodings.defined?(encoding)
|
177
|
+
raise UnknownEncodingType, "Don't know how to decode #{encoding}, please call #encoded and decode it yourself."
|
178
|
+
else
|
179
|
+
Encodings.get_encoding(encoding).decode(raw_source)
|
180
|
+
end
|
181
|
+
end
|
182
|
+
|
183
|
+
def to_s
|
184
|
+
decoded
|
185
|
+
end
|
186
|
+
|
187
|
+
def charset
|
188
|
+
@charset
|
189
|
+
end
|
190
|
+
|
191
|
+
def charset=( val )
|
192
|
+
@charset = val
|
193
|
+
end
|
194
|
+
|
195
|
+
def encoding(val = nil)
|
196
|
+
if val
|
197
|
+
self.encoding = val
|
198
|
+
else
|
199
|
+
@encoding
|
200
|
+
end
|
201
|
+
end
|
202
|
+
|
203
|
+
def encoding=( val )
|
204
|
+
@encoding = if val == "text" || val.blank?
|
205
|
+
(only_us_ascii? ? '7bit' : '8bit')
|
206
|
+
else
|
207
|
+
val
|
208
|
+
end
|
209
|
+
end
|
210
|
+
|
211
|
+
# Returns the preamble (any text that is before the first MIME boundary)
|
212
|
+
def preamble
|
213
|
+
@preamble
|
214
|
+
end
|
215
|
+
|
216
|
+
# Sets the preamble to a string (adds text before the first MIME boundary)
|
217
|
+
def preamble=( val )
|
218
|
+
@preamble = val
|
219
|
+
end
|
220
|
+
|
221
|
+
# Returns the epilogue (any text that is after the last MIME boundary)
|
222
|
+
def epilogue
|
223
|
+
@epilogue
|
224
|
+
end
|
225
|
+
|
226
|
+
# Sets the epilogue to a string (adds text after the last MIME boundary)
|
227
|
+
def epilogue=( val )
|
228
|
+
@epilogue = val
|
229
|
+
end
|
230
|
+
|
231
|
+
# Returns true if there are parts defined in the body
|
232
|
+
def multipart?
|
233
|
+
true unless parts.empty?
|
234
|
+
end
|
235
|
+
|
236
|
+
# Returns the boundary used by the body
|
237
|
+
def boundary
|
238
|
+
@boundary
|
239
|
+
end
|
240
|
+
|
241
|
+
# Allows you to change the boundary of this Body object
|
242
|
+
def boundary=( val )
|
243
|
+
@boundary = val
|
244
|
+
end
|
245
|
+
|
246
|
+
def parts
|
247
|
+
@parts
|
248
|
+
end
|
249
|
+
|
250
|
+
def <<( val )
|
251
|
+
if @parts
|
252
|
+
@parts << val
|
253
|
+
else
|
254
|
+
@parts = Mail::PartsList.new[val]
|
255
|
+
end
|
256
|
+
end
|
257
|
+
|
258
|
+
def split!(boundary)
|
259
|
+
self.boundary = boundary
|
260
|
+
parts = raw_source.split(/(?:\A|\r\n)--#{Regexp.escape(boundary || "")}(?=(?:--)?\s*$)/)
|
261
|
+
# Make the preamble equal to the preamble (if any)
|
262
|
+
self.preamble = parts[0].to_s.strip
|
263
|
+
# Make the epilogue equal to the epilogue (if any)
|
264
|
+
self.epilogue = parts[-1].to_s.sub('--', '').strip
|
265
|
+
parts[1...-1].to_a.each { |part| @parts << Mail::Part.new(part) }
|
266
|
+
self
|
267
|
+
end
|
268
|
+
|
269
|
+
def only_us_ascii?
|
270
|
+
!(raw_source =~ /[^\x01-\x7f]/)
|
271
|
+
end
|
272
|
+
|
273
|
+
def empty?
|
274
|
+
!!raw_source.to_s.empty?
|
275
|
+
end
|
276
|
+
|
277
|
+
private
|
278
|
+
|
279
|
+
def crlf_boundary
|
280
|
+
"\r\n--#{boundary}\r\n"
|
281
|
+
end
|
282
|
+
|
283
|
+
def end_boundary
|
284
|
+
"\r\n--#{boundary}--\r\n"
|
285
|
+
end
|
286
|
+
|
287
|
+
def set_charset
|
288
|
+
only_us_ascii? ? @charset = 'US-ASCII' : @charset = nil
|
289
|
+
end
|
290
|
+
end
|
291
|
+
end
|