mail 2.6.1 → 2.7.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 +92 -80
- data/lib/mail/attachments_list.rb +11 -5
- data/lib/mail/body.rb +81 -44
- data/lib/mail/check_delivery_params.rb +50 -10
- data/lib/mail/configuration.rb +3 -0
- data/lib/mail/{patterns.rb → constants.rb} +26 -6
- data/lib/mail/core_extensions/smtp.rb +20 -16
- data/lib/mail/core_extensions/string.rb +1 -27
- data/lib/mail/elements/address.rb +81 -93
- data/lib/mail/elements/address_list.rb +12 -29
- data/lib/mail/elements/content_disposition_element.rb +9 -15
- data/lib/mail/elements/content_location_element.rb +8 -12
- data/lib/mail/elements/content_transfer_encoding_element.rb +6 -10
- data/lib/mail/elements/content_type_element.rb +9 -19
- data/lib/mail/elements/date_time_element.rb +7 -14
- data/lib/mail/elements/envelope_from_element.rb +15 -21
- data/lib/mail/elements/message_ids_element.rb +12 -14
- data/lib/mail/elements/mime_version_element.rb +7 -14
- data/lib/mail/elements/phrase_list.rb +7 -9
- data/lib/mail/elements/received_element.rb +10 -15
- data/lib/mail/elements.rb +1 -0
- data/lib/mail/encodings/7bit.rb +6 -15
- 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 +121 -82
- data/lib/mail/envelope.rb +2 -1
- data/lib/mail/field.rb +114 -62
- data/lib/mail/field_list.rb +2 -1
- data/lib/mail/fields/bcc_field.rb +17 -5
- data/lib/mail/fields/cc_field.rb +2 -2
- data/lib/mail/fields/comments_field.rb +2 -1
- data/lib/mail/fields/common/address_container.rb +3 -2
- data/lib/mail/fields/common/common_address.rb +40 -14
- data/lib/mail/fields/common/common_date.rb +2 -1
- data/lib/mail/fields/common/common_field.rb +6 -11
- data/lib/mail/fields/common/common_message_id.rb +3 -2
- data/lib/mail/fields/common/parameter_hash.rb +5 -4
- data/lib/mail/fields/content_description_field.rb +2 -1
- data/lib/mail/fields/content_disposition_field.rb +14 -13
- data/lib/mail/fields/content_id_field.rb +5 -4
- data/lib/mail/fields/content_location_field.rb +3 -2
- data/lib/mail/fields/content_transfer_encoding_field.rb +3 -2
- data/lib/mail/fields/content_type_field.rb +7 -11
- data/lib/mail/fields/date_field.rb +4 -4
- data/lib/mail/fields/from_field.rb +2 -2
- data/lib/mail/fields/in_reply_to_field.rb +2 -1
- data/lib/mail/fields/keywords_field.rb +3 -3
- data/lib/mail/fields/message_id_field.rb +3 -2
- data/lib/mail/fields/mime_version_field.rb +4 -3
- data/lib/mail/fields/optional_field.rb +5 -1
- data/lib/mail/fields/received_field.rb +5 -4
- data/lib/mail/fields/references_field.rb +2 -1
- data/lib/mail/fields/reply_to_field.rb +2 -2
- data/lib/mail/fields/resent_bcc_field.rb +2 -2
- data/lib/mail/fields/resent_cc_field.rb +2 -2
- data/lib/mail/fields/resent_date_field.rb +2 -2
- data/lib/mail/fields/resent_from_field.rb +2 -2
- data/lib/mail/fields/resent_message_id_field.rb +2 -1
- data/lib/mail/fields/resent_sender_field.rb +2 -2
- data/lib/mail/fields/resent_to_field.rb +2 -2
- data/lib/mail/fields/return_path_field.rb +2 -2
- data/lib/mail/fields/sender_field.rb +2 -2
- data/lib/mail/fields/structured_field.rb +1 -0
- data/lib/mail/fields/subject_field.rb +2 -1
- data/lib/mail/fields/to_field.rb +2 -2
- data/lib/mail/fields/unstructured_field.rb +28 -10
- data/lib/mail/fields.rb +1 -0
- data/lib/mail/header.rb +18 -14
- data/lib/mail/indifferent_hash.rb +1 -0
- data/lib/mail/mail.rb +6 -11
- data/lib/mail/matchers/attachment_matchers.rb +29 -0
- data/lib/mail/matchers/has_sent_mail.rb +53 -9
- data/lib/mail/message.rb +99 -89
- data/lib/mail/multibyte/chars.rb +32 -30
- data/lib/mail/multibyte/unicode.rb +31 -26
- data/lib/mail/multibyte/utils.rb +1 -0
- data/lib/mail/multibyte.rb +65 -15
- data/lib/mail/network/delivery_methods/exim.rb +7 -10
- data/lib/mail/network/delivery_methods/file_delivery.rb +5 -8
- data/lib/mail/network/delivery_methods/logger_delivery.rb +37 -0
- data/lib/mail/network/delivery_methods/sendmail.rb +17 -11
- data/lib/mail/network/delivery_methods/smtp.rb +60 -53
- data/lib/mail/network/delivery_methods/smtp_connection.rb +11 -6
- data/lib/mail/network/delivery_methods/test_mailer.rb +6 -8
- data/lib/mail/network/retriever_methods/base.rb +1 -0
- data/lib/mail/network/retriever_methods/imap.rb +19 -5
- data/lib/mail/network/retriever_methods/pop3.rb +4 -1
- data/lib/mail/network/retriever_methods/test_retriever.rb +2 -1
- data/lib/mail/network.rb +2 -0
- data/lib/mail/parser_tools.rb +15 -0
- data/lib/mail/parsers/address_lists_parser.rb +33208 -104
- data/lib/mail/parsers/address_lists_parser.rl +172 -0
- data/lib/mail/parsers/content_disposition_parser.rb +877 -49
- data/lib/mail/parsers/content_disposition_parser.rl +82 -0
- data/lib/mail/parsers/content_location_parser.rb +804 -23
- data/lib/mail/parsers/content_location_parser.rl +71 -0
- data/lib/mail/parsers/content_transfer_encoding_parser.rb +502 -19
- data/lib/mail/parsers/content_transfer_encoding_parser.rl +64 -0
- data/lib/mail/parsers/content_type_parser.rb +1024 -46
- data/lib/mail/parsers/content_type_parser.rl +83 -0
- data/lib/mail/parsers/date_time_parser.rb +872 -23
- data/lib/mail/parsers/date_time_parser.rl +62 -0
- data/lib/mail/parsers/envelope_from_parser.rb +3570 -34
- data/lib/mail/parsers/envelope_from_parser.rl +82 -0
- data/lib/mail/parsers/message_ids_parser.rb +2840 -25
- data/lib/mail/parsers/message_ids_parser.rl +82 -0
- data/lib/mail/parsers/mime_version_parser.rb +492 -26
- data/lib/mail/parsers/mime_version_parser.rl +61 -0
- data/lib/mail/parsers/phrase_lists_parser.rb +862 -17
- data/lib/mail/parsers/phrase_lists_parser.rl +83 -0
- data/lib/mail/parsers/received_parser.rb +8765 -36
- data/lib/mail/parsers/received_parser.rl +84 -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 +59 -0
- data/lib/mail/parsers/rfc5322_address.rl +72 -0
- data/lib/mail/parsers/{ragel/date_time.rl → rfc5322_date_time.rl} +8 -1
- data/lib/mail/parsers/rfc5322_lexical_tokens.rl +60 -0
- data/lib/mail/parsers.rb +17 -24
- data/lib/mail/part.rb +8 -5
- data/lib/mail/parts_list.rb +31 -14
- data/lib/mail/utilities.rb +112 -13
- data/lib/mail/values/unicode_tables.dat +0 -0
- data/lib/mail/version.rb +8 -15
- data/lib/mail/version_specific/ruby_1_8.rb +52 -8
- data/lib/mail/version_specific/ruby_1_9.rb +143 -24
- data/lib/mail.rb +8 -14
- metadata +71 -81
- data/CHANGELOG.rdoc +0 -752
- data/CONTRIBUTING.md +0 -60
- data/Dependencies.txt +0 -2
- data/Gemfile +0 -15
- data/Rakefile +0 -29
- data/TODO.rdoc +0 -9
- data/VERSION +0 -4
- data/lib/mail/core_extensions/nil.rb +0 -19
- data/lib/mail/core_extensions/object.rb +0 -13
- data/lib/mail/core_extensions/string/access.rb +0 -145
- data/lib/mail/core_extensions/string/multibyte.rb +0 -78
- data/lib/mail/multibyte/exceptions.rb +0 -8
- data/lib/mail/parsers/ragel/common.rl +0 -184
- data/lib/mail/parsers/ragel/parser_info.rb +0 -61
- data/lib/mail/parsers/ragel/ruby/machines/address_lists_machine.rb +0 -14864
- data/lib/mail/parsers/ragel/ruby/machines/address_lists_machine.rb.rl +0 -37
- data/lib/mail/parsers/ragel/ruby/machines/content_disposition_machine.rb +0 -751
- data/lib/mail/parsers/ragel/ruby/machines/content_disposition_machine.rb.rl +0 -37
- data/lib/mail/parsers/ragel/ruby/machines/content_location_machine.rb +0 -614
- data/lib/mail/parsers/ragel/ruby/machines/content_location_machine.rb.rl +0 -37
- data/lib/mail/parsers/ragel/ruby/machines/content_transfer_encoding_machine.rb +0 -447
- data/lib/mail/parsers/ragel/ruby/machines/content_transfer_encoding_machine.rb.rl +0 -37
- data/lib/mail/parsers/ragel/ruby/machines/content_type_machine.rb +0 -825
- data/lib/mail/parsers/ragel/ruby/machines/content_type_machine.rb.rl +0 -37
- data/lib/mail/parsers/ragel/ruby/machines/date_time_machine.rb +0 -817
- data/lib/mail/parsers/ragel/ruby/machines/date_time_machine.rb.rl +0 -37
- data/lib/mail/parsers/ragel/ruby/machines/envelope_from_machine.rb +0 -2129
- data/lib/mail/parsers/ragel/ruby/machines/envelope_from_machine.rb.rl +0 -37
- data/lib/mail/parsers/ragel/ruby/machines/message_ids_machine.rb +0 -1570
- data/lib/mail/parsers/ragel/ruby/machines/message_ids_machine.rb.rl +0 -37
- data/lib/mail/parsers/ragel/ruby/machines/mime_version_machine.rb +0 -440
- data/lib/mail/parsers/ragel/ruby/machines/mime_version_machine.rb.rl +0 -37
- data/lib/mail/parsers/ragel/ruby/machines/phrase_lists_machine.rb +0 -564
- data/lib/mail/parsers/ragel/ruby/machines/phrase_lists_machine.rb.rl +0 -37
- data/lib/mail/parsers/ragel/ruby/machines/rb_actions.rl +0 -51
- data/lib/mail/parsers/ragel/ruby/machines/received_machine.rb +0 -5144
- data/lib/mail/parsers/ragel/ruby/machines/received_machine.rb.rl +0 -37
- data/lib/mail/parsers/ragel/ruby/parser.rb.rl.erb +0 -37
- data/lib/mail/parsers/ragel/ruby.rb +0 -39
- data/lib/mail/parsers/ragel.rb +0 -17
@@ -1,6 +1,27 @@
|
|
1
|
+
# frozen_string_literal: true
|
1
2
|
module Mail
|
2
3
|
module Multibyte
|
3
4
|
module Unicode
|
5
|
+
# Adapted from https://github.com/rails/rails/blob/master/activesupport/lib/active_support/multibyte/unicode.rb
|
6
|
+
# under the MIT license
|
7
|
+
# The Unicode version that is supported by the implementation
|
8
|
+
UNICODE_VERSION = '7.0.0'
|
9
|
+
|
10
|
+
# Holds data about a codepoint in the Unicode database.
|
11
|
+
class Codepoint
|
12
|
+
attr_accessor :code, :combining_class, :decomp_type, :decomp_mapping, :uppercase_mapping, :lowercase_mapping
|
13
|
+
|
14
|
+
# Initializing Codepoint object with default values
|
15
|
+
def initialize
|
16
|
+
@combining_class = 0
|
17
|
+
@uppercase_mapping = 0
|
18
|
+
@lowercase_mapping = 0
|
19
|
+
end
|
20
|
+
|
21
|
+
def swapcase_mapping
|
22
|
+
uppercase_mapping > 0 ? uppercase_mapping : lowercase_mapping
|
23
|
+
end
|
24
|
+
end
|
4
25
|
|
5
26
|
extend self
|
6
27
|
|
@@ -8,9 +29,6 @@ module Mail
|
|
8
29
|
# information about normalization.
|
9
30
|
NORMALIZATION_FORMS = [:c, :kc, :d, :kd]
|
10
31
|
|
11
|
-
# The Unicode version that is supported by the implementation
|
12
|
-
UNICODE_VERSION = '5.2.0'
|
13
|
-
|
14
32
|
# The default normalization used for operations that require normalization. It can be set to any of the
|
15
33
|
# normalizations in NORMALIZATION_FORMS.
|
16
34
|
#
|
@@ -284,16 +302,16 @@ module Mail
|
|
284
302
|
# See http://www.unicode.org/reports/tr15, Table 1
|
285
303
|
codepoints = u_unpack(string)
|
286
304
|
case form
|
287
|
-
|
288
|
-
|
289
|
-
|
290
|
-
|
291
|
-
|
292
|
-
|
293
|
-
|
294
|
-
|
295
|
-
|
296
|
-
|
305
|
+
when :d
|
306
|
+
reorder_characters(decompose_codepoints(:canonical, codepoints))
|
307
|
+
when :c
|
308
|
+
compose_codepoints(reorder_characters(decompose_codepoints(:canonical, codepoints)))
|
309
|
+
when :kd
|
310
|
+
reorder_characters(decompose_codepoints(:compatability, codepoints))
|
311
|
+
when :kc
|
312
|
+
compose_codepoints(reorder_characters(decompose_codepoints(:compatability, codepoints)))
|
313
|
+
else
|
314
|
+
raise ArgumentError, "#{form} is not a valid normalization variant", caller
|
297
315
|
end.pack('U*')
|
298
316
|
end
|
299
317
|
|
@@ -308,11 +326,6 @@ module Mail
|
|
308
326
|
end.pack('U*')
|
309
327
|
end
|
310
328
|
|
311
|
-
# Holds data about a codepoint in the Unicode database
|
312
|
-
class Codepoint
|
313
|
-
attr_accessor :code, :combining_class, :decomp_type, :decomp_mapping, :uppercase_mapping, :lowercase_mapping
|
314
|
-
end
|
315
|
-
|
316
329
|
# Holds static data from the Unicode database
|
317
330
|
class UnicodeDatabase
|
318
331
|
ATTRIBUTES = :codepoints, :composition_exclusion, :composition_map, :boundary, :cp1252
|
@@ -390,11 +403,3 @@ module Mail
|
|
390
403
|
end
|
391
404
|
end
|
392
405
|
end
|
393
|
-
|
394
|
-
unless defined?(ActiveSupport)
|
395
|
-
module ActiveSupport
|
396
|
-
unless const_defined?(:Multibyte)
|
397
|
-
Multibyte = Mail::Multibyte
|
398
|
-
end
|
399
|
-
end
|
400
|
-
end
|
data/lib/mail/multibyte/utils.rb
CHANGED
data/lib/mail/multibyte.rb
CHANGED
@@ -1,23 +1,73 @@
|
|
1
1
|
# encoding: utf-8
|
2
|
+
# frozen_string_literal: true
|
3
|
+
require 'mail/multibyte/chars'
|
4
|
+
|
2
5
|
module Mail #:nodoc:
|
3
6
|
module Multibyte
|
4
|
-
|
5
|
-
|
6
|
-
require 'mail/multibyte/unicode'
|
7
|
+
# Raised when a problem with the encoding was found.
|
8
|
+
class EncodingError < StandardError; end
|
7
9
|
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
10
|
+
class << self
|
11
|
+
# The proxy class returned when calling mb_chars. You can use this accessor to configure your own proxy
|
12
|
+
# class so you can support other encodings. See the Mail::Multibyte::Chars implementation for
|
13
|
+
# an example how to do this.
|
14
|
+
#
|
15
|
+
# Example:
|
16
|
+
# Mail::Multibyte.proxy_class = CharsForUTF32
|
17
|
+
attr_accessor :proxy_class
|
16
18
|
end
|
17
19
|
|
18
|
-
|
19
|
-
|
20
|
-
|
20
|
+
self.proxy_class = Mail::Multibyte::Chars
|
21
|
+
|
22
|
+
if RUBY_VERSION >= "1.9"
|
23
|
+
# == Multibyte proxy
|
24
|
+
#
|
25
|
+
# +mb_chars+ is a multibyte safe proxy for string methods.
|
26
|
+
#
|
27
|
+
# In Ruby 1.8 and older it creates and returns an instance of the Mail::Multibyte::Chars class which
|
28
|
+
# encapsulates the original string. A Unicode safe version of all the String methods are defined on this proxy
|
29
|
+
# class. If the proxy class doesn't respond to a certain method, it's forwarded to the encapsuled string.
|
30
|
+
#
|
31
|
+
# name = 'Claus Müller'
|
32
|
+
# name.reverse # => "rell??M sualC"
|
33
|
+
# name.length # => 13
|
34
|
+
#
|
35
|
+
# name.mb_chars.reverse.to_s # => "rellüM sualC"
|
36
|
+
# name.mb_chars.length # => 12
|
37
|
+
#
|
38
|
+
# In Ruby 1.9 and newer +mb_chars+ returns +self+ because String is (mostly) encoding aware. This means that
|
39
|
+
# it becomes easy to run one version of your code on multiple Ruby versions.
|
40
|
+
#
|
41
|
+
# == Method chaining
|
42
|
+
#
|
43
|
+
# All the methods on the Chars proxy which normally return a string will return a Chars object. This allows
|
44
|
+
# method chaining on the result of any of these methods.
|
45
|
+
#
|
46
|
+
# name.mb_chars.reverse.length # => 12
|
47
|
+
#
|
48
|
+
# == Interoperability and configuration
|
49
|
+
#
|
50
|
+
# The Chars object tries to be as interchangeable with String objects as possible: sorting and comparing between
|
51
|
+
# String and Char work like expected. The bang! methods change the internal string representation in the Chars
|
52
|
+
# object. Interoperability problems can be resolved easily with a +to_s+ call.
|
53
|
+
#
|
54
|
+
# For more information about the methods defined on the Chars proxy see Mail::Multibyte::Chars. For
|
55
|
+
# information about how to change the default Multibyte behaviour see Mail::Multibyte.
|
56
|
+
def self.mb_chars(str)
|
57
|
+
if proxy_class.consumes?(str)
|
58
|
+
proxy_class.new(str)
|
59
|
+
else
|
60
|
+
str
|
61
|
+
end
|
62
|
+
end
|
63
|
+
else
|
64
|
+
def self.mb_chars(str)
|
65
|
+
if proxy_class.wants?(str)
|
66
|
+
proxy_class.new(str)
|
67
|
+
else
|
68
|
+
str
|
69
|
+
end
|
70
|
+
end
|
21
71
|
end
|
22
72
|
|
23
73
|
# Regular expressions that describe valid byte sequences for a character
|
@@ -39,4 +89,4 @@ module Mail #:nodoc:
|
|
39
89
|
end
|
40
90
|
end
|
41
91
|
|
42
|
-
require 'mail/multibyte/utils'
|
92
|
+
require 'mail/multibyte/utils'
|
@@ -1,3 +1,4 @@
|
|
1
|
+
# frozen_string_literal: true
|
1
2
|
module Mail
|
2
3
|
|
3
4
|
# A delivery method implementation which sends via exim.
|
@@ -36,17 +37,13 @@ module Mail
|
|
36
37
|
#
|
37
38
|
# mail.deliver!
|
38
39
|
class Exim < Sendmail
|
39
|
-
|
40
|
-
|
41
|
-
|
42
|
-
|
40
|
+
DEFAULTS = {
|
41
|
+
:location => '/usr/sbin/exim',
|
42
|
+
:arguments => '-i -t'
|
43
|
+
}
|
43
44
|
|
44
|
-
def self.call(path, arguments, destinations,
|
45
|
-
|
46
|
-
io.puts mail.encoded.to_lf
|
47
|
-
io.flush
|
48
|
-
end
|
45
|
+
def self.call(path, arguments, destinations, encoded_message)
|
46
|
+
super path, arguments, nil, encoded_message
|
49
47
|
end
|
50
|
-
|
51
48
|
end
|
52
49
|
end
|
@@ -1,7 +1,7 @@
|
|
1
|
+
# frozen_string_literal: true
|
1
2
|
require 'mail/check_delivery_params'
|
2
3
|
|
3
4
|
module Mail
|
4
|
-
|
5
5
|
# FileDelivery class delivers emails into multiple files based on the destination
|
6
6
|
# address. Each file is appended to if it already exists.
|
7
7
|
#
|
@@ -13,22 +13,20 @@ module Mail
|
|
13
13
|
# Make sure the path you specify with :location is writable by the Ruby process
|
14
14
|
# running Mail.
|
15
15
|
class FileDelivery
|
16
|
-
include Mail::CheckDeliveryParams
|
17
|
-
|
18
16
|
if RUBY_VERSION >= '1.9.1'
|
19
17
|
require 'fileutils'
|
20
18
|
else
|
21
19
|
require 'ftools'
|
22
20
|
end
|
23
21
|
|
22
|
+
attr_accessor :settings
|
23
|
+
|
24
24
|
def initialize(values)
|
25
25
|
self.settings = { :location => './mails' }.merge!(values)
|
26
26
|
end
|
27
|
-
|
28
|
-
attr_accessor :settings
|
29
|
-
|
27
|
+
|
30
28
|
def deliver!(mail)
|
31
|
-
|
29
|
+
Mail::CheckDeliveryParams.check(mail)
|
32
30
|
|
33
31
|
if ::File.respond_to?(:makedirs)
|
34
32
|
::File.makedirs settings[:location]
|
@@ -40,6 +38,5 @@ module Mail
|
|
40
38
|
::File.open(::File.join(settings[:location], File.basename(to.to_s)), 'a') { |f| "#{f.write(mail.encoded)}\r\n\r\n" }
|
41
39
|
end
|
42
40
|
end
|
43
|
-
|
44
41
|
end
|
45
42
|
end
|
@@ -0,0 +1,37 @@
|
|
1
|
+
require 'mail/check_delivery_params'
|
2
|
+
|
3
|
+
module Mail
|
4
|
+
class LoggerDelivery
|
5
|
+
include Mail::CheckDeliveryParams
|
6
|
+
|
7
|
+
attr_reader :logger, :severity, :settings
|
8
|
+
|
9
|
+
def initialize(settings)
|
10
|
+
@settings = settings
|
11
|
+
@logger = settings.fetch(:logger) { default_logger }
|
12
|
+
@severity = derive_severity(settings[:severity])
|
13
|
+
end
|
14
|
+
|
15
|
+
def deliver!(mail)
|
16
|
+
Mail::CheckDeliveryParams.check(mail)
|
17
|
+
logger.log(severity) { mail.encoded }
|
18
|
+
end
|
19
|
+
|
20
|
+
private
|
21
|
+
def default_logger
|
22
|
+
require 'logger'
|
23
|
+
::Logger.new($stdout)
|
24
|
+
end
|
25
|
+
|
26
|
+
def derive_severity(severity)
|
27
|
+
case severity
|
28
|
+
when nil
|
29
|
+
Logger::INFO
|
30
|
+
when Integer
|
31
|
+
severity
|
32
|
+
else
|
33
|
+
Logger.const_get(severity.to_s.upcase)
|
34
|
+
end
|
35
|
+
end
|
36
|
+
end
|
37
|
+
end
|
@@ -1,3 +1,4 @@
|
|
1
|
+
# frozen_string_literal: true
|
1
2
|
require 'mail/check_delivery_params'
|
2
3
|
|
3
4
|
module Mail
|
@@ -37,19 +38,21 @@ module Mail
|
|
37
38
|
#
|
38
39
|
# mail.deliver!
|
39
40
|
class Sendmail
|
40
|
-
|
41
|
+
DEFAULTS = {
|
42
|
+
:location => '/usr/sbin/sendmail',
|
43
|
+
:arguments => '-i'
|
44
|
+
}
|
45
|
+
|
46
|
+
attr_accessor :settings
|
41
47
|
|
42
48
|
def initialize(values)
|
43
|
-
self.settings =
|
44
|
-
:arguments => '-i' }.merge(values)
|
49
|
+
self.settings = self.class::DEFAULTS.merge(values)
|
45
50
|
end
|
46
51
|
|
47
|
-
attr_accessor :settings
|
48
|
-
|
49
52
|
def deliver!(mail)
|
50
|
-
smtp_from, smtp_to, message =
|
53
|
+
smtp_from, smtp_to, message = Mail::CheckDeliveryParams.check(mail)
|
51
54
|
|
52
|
-
from = "-f #{self.class.shellquote(smtp_from)}"
|
55
|
+
from = "-f #{self.class.shellquote(smtp_from)}" if smtp_from
|
53
56
|
to = smtp_to.map { |_to| self.class.shellquote(_to) }.join(' ')
|
54
57
|
|
55
58
|
arguments = "#{settings[:arguments]} #{from} --"
|
@@ -58,7 +61,7 @@ module Mail
|
|
58
61
|
|
59
62
|
def self.call(path, arguments, destinations, encoded_message)
|
60
63
|
popen "#{path} #{arguments} #{destinations}" do |io|
|
61
|
-
io.puts encoded_message
|
64
|
+
io.puts ::Mail::Utilities.binary_unsafe_to_lf(encoded_message)
|
62
65
|
io.flush
|
63
66
|
end
|
64
67
|
end
|
@@ -74,15 +77,18 @@ module Mail
|
|
74
77
|
end
|
75
78
|
|
76
79
|
# The following is an adaptation of ruby 1.9.2's shellwords.rb file,
|
77
|
-
#
|
78
|
-
#
|
80
|
+
# with the following modifications:
|
81
|
+
#
|
82
|
+
# - Wraps in double quotes
|
83
|
+
# - Allows '+' to accept email addresses with them
|
84
|
+
# - Allows '~' as it is not unescaped in double quotes
|
79
85
|
def self.shellquote(address)
|
80
86
|
# Process as a single byte sequence because not all shell
|
81
87
|
# implementations are multibyte aware.
|
82
88
|
#
|
83
89
|
# A LF cannot be escaped with a backslash because a backslash + LF
|
84
90
|
# combo is regarded as line continuation and simply ignored. Strip it.
|
85
|
-
escaped = address.gsub(/([^A-Za-z0-9_\s
|
91
|
+
escaped = address.gsub(/([^A-Za-z0-9_\s\+\-.,:\/@~])/n, "\\\\\\1").gsub("\n", '')
|
86
92
|
%("#{escaped}")
|
87
93
|
end
|
88
94
|
end
|
@@ -1,3 +1,4 @@
|
|
1
|
+
# frozen_string_literal: true
|
1
2
|
require 'mail/check_delivery_params'
|
2
3
|
|
3
4
|
module Mail
|
@@ -44,9 +45,8 @@ module Mail
|
|
44
45
|
# hostname or update the certificate authorities trusted by your ruby. If
|
45
46
|
# that isn't possible, you can control this behavior with
|
46
47
|
# an :openssl_verify_mode setting. Its value may be either an OpenSSL
|
47
|
-
# verify mode constant (OpenSSL::SSL::VERIFY_NONE),
|
48
|
-
# the name of an OpenSSL verify mode (none, peer
|
49
|
-
# fail_if_no_peer_cert).
|
48
|
+
# verify mode constant (OpenSSL::SSL::VERIFY_NONE, OpenSSL::SSL::VERIFY_PEER),
|
49
|
+
# or a string containing the name of an OpenSSL verify mode (none, peer).
|
50
50
|
#
|
51
51
|
# === Others
|
52
52
|
#
|
@@ -74,69 +74,76 @@ module Mail
|
|
74
74
|
#
|
75
75
|
# mail.deliver!
|
76
76
|
class SMTP
|
77
|
-
|
77
|
+
attr_accessor :settings
|
78
|
+
|
79
|
+
DEFAULTS = {
|
80
|
+
:address => 'localhost',
|
81
|
+
:port => 25,
|
82
|
+
:domain => 'localhost.localdomain',
|
83
|
+
:user_name => nil,
|
84
|
+
:password => nil,
|
85
|
+
:authentication => nil,
|
86
|
+
:enable_starttls => nil,
|
87
|
+
:enable_starttls_auto => true,
|
88
|
+
:openssl_verify_mode => nil,
|
89
|
+
:ssl => nil,
|
90
|
+
:tls => nil,
|
91
|
+
:open_timeout => nil,
|
92
|
+
:read_timeout => nil
|
93
|
+
}
|
78
94
|
|
79
95
|
def initialize(values)
|
80
|
-
self.settings =
|
81
|
-
:port => 25,
|
82
|
-
:domain => 'localhost.localdomain',
|
83
|
-
:user_name => nil,
|
84
|
-
:password => nil,
|
85
|
-
:authentication => nil,
|
86
|
-
:enable_starttls_auto => true,
|
87
|
-
:openssl_verify_mode => nil,
|
88
|
-
:ssl => nil,
|
89
|
-
:tls => nil
|
90
|
-
}.merge!(values)
|
96
|
+
self.settings = DEFAULTS.merge(values)
|
91
97
|
end
|
92
98
|
|
93
|
-
attr_accessor :settings
|
94
|
-
|
95
|
-
# Send the message via SMTP.
|
96
|
-
# The from and to attributes are optional. If not set, they are retrieve from the Message.
|
97
99
|
def deliver!(mail)
|
98
|
-
|
99
|
-
|
100
|
-
smtp = Net::SMTP.new(settings[:address], settings[:port])
|
101
|
-
if settings[:tls] || settings[:ssl]
|
102
|
-
if smtp.respond_to?(:enable_tls)
|
103
|
-
smtp.enable_tls(ssl_context)
|
104
|
-
end
|
105
|
-
elsif settings[:enable_starttls_auto]
|
106
|
-
if smtp.respond_to?(:enable_starttls_auto)
|
107
|
-
smtp.enable_starttls_auto(ssl_context)
|
108
|
-
end
|
109
|
-
end
|
110
|
-
|
111
|
-
response = nil
|
112
|
-
smtp.start(settings[:domain], settings[:user_name], settings[:password], settings[:authentication]) do |smtp_obj|
|
113
|
-
response = smtp_obj.sendmail(message, smtp_from, smtp_to)
|
100
|
+
response = start_smtp_session do |smtp|
|
101
|
+
Mail::SMTPConnection.new(:connection => smtp, :return_response => true).deliver!(mail)
|
114
102
|
end
|
115
103
|
|
116
|
-
|
117
|
-
response
|
118
|
-
else
|
119
|
-
self
|
120
|
-
end
|
104
|
+
settings[:return_response] ? response : self
|
121
105
|
end
|
122
|
-
|
123
106
|
|
124
107
|
private
|
108
|
+
def start_smtp_session(&block)
|
109
|
+
build_smtp_session.start(settings[:domain], settings[:user_name], settings[:password], settings[:authentication], &block)
|
110
|
+
end
|
125
111
|
|
126
|
-
|
127
|
-
|
128
|
-
|
129
|
-
|
112
|
+
def build_smtp_session
|
113
|
+
Net::SMTP.new(settings[:address], settings[:port]).tap do |smtp|
|
114
|
+
if settings[:tls] || settings[:ssl]
|
115
|
+
if smtp.respond_to?(:enable_tls)
|
116
|
+
smtp.enable_tls(ssl_context)
|
117
|
+
end
|
118
|
+
elsif settings[:enable_starttls]
|
119
|
+
if smtp.respond_to?(:enable_starttls)
|
120
|
+
smtp.enable_starttls(ssl_context)
|
121
|
+
end
|
122
|
+
elsif settings[:enable_starttls_auto]
|
123
|
+
if smtp.respond_to?(:enable_starttls_auto)
|
124
|
+
smtp.enable_starttls_auto(ssl_context)
|
125
|
+
end
|
126
|
+
end
|
130
127
|
|
131
|
-
|
132
|
-
|
128
|
+
smtp.open_timeout = settings[:open_timeout] if settings[:open_timeout]
|
129
|
+
smtp.read_timeout = settings[:read_timeout] if settings[:read_timeout]
|
130
|
+
end
|
133
131
|
end
|
134
132
|
|
135
|
-
context
|
136
|
-
|
137
|
-
|
138
|
-
|
139
|
-
|
140
|
-
|
133
|
+
# Allow SSL context to be configured via settings, for Ruby >= 1.9
|
134
|
+
# Just returns openssl verify mode for Ruby 1.8.x
|
135
|
+
def ssl_context
|
136
|
+
openssl_verify_mode = settings[:openssl_verify_mode]
|
137
|
+
|
138
|
+
if openssl_verify_mode.kind_of?(String)
|
139
|
+
openssl_verify_mode = OpenSSL::SSL.const_get("VERIFY_#{openssl_verify_mode.upcase}")
|
140
|
+
end
|
141
|
+
|
142
|
+
context = Net::SMTP.default_ssl_context
|
143
|
+
context.verify_mode = openssl_verify_mode if openssl_verify_mode
|
144
|
+
context.ca_path = settings[:ca_path] if settings[:ca_path]
|
145
|
+
context.ca_file = settings[:ca_file] if settings[:ca_file]
|
146
|
+
context
|
147
|
+
end
|
141
148
|
end
|
142
149
|
end
|
@@ -1,3 +1,4 @@
|
|
1
|
+
# frozen_string_literal: true
|
1
2
|
require 'mail/check_delivery_params'
|
2
3
|
|
3
4
|
module Mail
|
@@ -37,7 +38,7 @@ module Mail
|
|
37
38
|
#
|
38
39
|
# mail.deliver!
|
39
40
|
class SMTPConnection
|
40
|
-
|
41
|
+
attr_accessor :smtp, :settings
|
41
42
|
|
42
43
|
def initialize(values)
|
43
44
|
raise ArgumentError.new('A Net::SMTP object is required for this delivery method') if values[:connection].nil?
|
@@ -45,17 +46,21 @@ module Mail
|
|
45
46
|
self.settings = values
|
46
47
|
end
|
47
48
|
|
48
|
-
attr_accessor :smtp
|
49
|
-
attr_accessor :settings
|
50
|
-
|
51
49
|
# Send the message via SMTP.
|
52
50
|
# The from and to attributes are optional. If not set, they are retrieve from the Message.
|
53
51
|
def deliver!(mail)
|
54
|
-
smtp_from, smtp_to, message =
|
55
|
-
|
52
|
+
smtp_from, smtp_to, message = Mail::CheckDeliveryParams.check(mail)
|
53
|
+
|
54
|
+
response = smtp.sendmail(dot_stuff(message), smtp_from, smtp_to)
|
56
55
|
|
57
56
|
settings[:return_response] ? response : self
|
58
57
|
end
|
59
58
|
|
59
|
+
private
|
60
|
+
# This is Net::SMTP's job, but before Ruby 2.x it does not dot-stuff
|
61
|
+
# an unterminated last line: https://bugs.ruby-lang.org/issues/9627
|
62
|
+
def dot_stuff(message)
|
63
|
+
message.gsub(/(\r\n\.)(\r\n|$)/, '\1.\2')
|
64
|
+
end
|
60
65
|
end
|
61
66
|
end
|
@@ -1,3 +1,4 @@
|
|
1
|
+
# frozen_string_literal: true
|
1
2
|
require 'mail/check_delivery_params'
|
2
3
|
|
3
4
|
module Mail
|
@@ -7,10 +8,8 @@ module Mail
|
|
7
8
|
# It also provides a template of the minimum methods you require to implement
|
8
9
|
# if you want to make a custom mailer for Mail
|
9
10
|
class TestMailer
|
10
|
-
include Mail::CheckDeliveryParams
|
11
|
-
|
12
11
|
# Provides a store of all the emails sent with the TestMailer so you can check them.
|
13
|
-
def
|
12
|
+
def self.deliveries
|
14
13
|
@@deliveries ||= []
|
15
14
|
end
|
16
15
|
|
@@ -25,20 +24,19 @@ module Mail
|
|
25
24
|
# * length
|
26
25
|
# * size
|
27
26
|
# * and other common Array methods
|
28
|
-
def
|
27
|
+
def self.deliveries=(val)
|
29
28
|
@@deliveries = val
|
30
29
|
end
|
31
30
|
|
31
|
+
attr_accessor :settings
|
32
|
+
|
32
33
|
def initialize(values)
|
33
34
|
@settings = values.dup
|
34
35
|
end
|
35
|
-
|
36
|
-
attr_accessor :settings
|
37
36
|
|
38
37
|
def deliver!(mail)
|
39
|
-
|
38
|
+
Mail::CheckDeliveryParams.check(mail)
|
40
39
|
Mail::TestMailer.deliveries << mail
|
41
40
|
end
|
42
|
-
|
43
41
|
end
|
44
42
|
end
|
@@ -1,4 +1,5 @@
|
|
1
1
|
# encoding: utf-8
|
2
|
+
# frozen_string_literal: true
|
2
3
|
|
3
4
|
module Mail
|
4
5
|
# The IMAP retriever allows to get the last, first or all emails from a IMAP server.
|
@@ -44,7 +45,8 @@ module Mail
|
|
44
45
|
:user_name => nil,
|
45
46
|
:password => nil,
|
46
47
|
:authentication => nil,
|
47
|
-
:enable_ssl => false
|
48
|
+
:enable_ssl => false,
|
49
|
+
:enable_starttls => false }.merge!(values)
|
48
50
|
end
|
49
51
|
|
50
52
|
attr_accessor :settings
|
@@ -66,14 +68,14 @@ module Mail
|
|
66
68
|
# keys: are passed as criteria to the SEARCH command. They can either be a string holding the entire search string,
|
67
69
|
# or a single-dimension array of search keywords and arguments. Refer to [IMAP] section 6.4.4 for a full list
|
68
70
|
# The default is 'ALL'
|
71
|
+
# search_charset: charset to pass to IMAP server search. Omitted by default. Example: 'UTF-8' or 'ASCII'.
|
69
72
|
#
|
70
73
|
def find(options={}, &block)
|
71
74
|
options = validate_options(options)
|
72
75
|
|
73
76
|
start do |imap|
|
74
77
|
options[:read_only] ? imap.examine(options[:mailbox]) : imap.select(options[:mailbox])
|
75
|
-
|
76
|
-
uids = imap.uid_search(options[:keys])
|
78
|
+
uids = imap.uid_search(options[:keys], options[:search_charset])
|
77
79
|
uids.reverse! if options[:what].to_sym == :last
|
78
80
|
uids = uids.first(options[:count]) if options[:count].is_a?(Integer)
|
79
81
|
uids.reverse! if (options[:what].to_sym == :last && options[:order].to_sym == :asc) ||
|
@@ -82,14 +84,18 @@ module Mail
|
|
82
84
|
if block_given?
|
83
85
|
uids.each do |uid|
|
84
86
|
uid = options[:uid].to_i unless options[:uid].nil?
|
85
|
-
fetchdata = imap.uid_fetch(uid, ['RFC822'])[0]
|
87
|
+
fetchdata = imap.uid_fetch(uid, ['RFC822', 'FLAGS'])[0]
|
86
88
|
new_message = Mail.new(fetchdata.attr['RFC822'])
|
87
89
|
new_message.mark_for_delete = true if options[:delete_after_find]
|
88
|
-
|
90
|
+
|
91
|
+
if block.arity == 4
|
92
|
+
yield new_message, imap, uid, fetchdata.attr['FLAGS']
|
93
|
+
elsif block.arity == 3
|
89
94
|
yield new_message, imap, uid
|
90
95
|
else
|
91
96
|
yield new_message
|
92
97
|
end
|
98
|
+
|
93
99
|
imap.uid_store(uid, "+FLAGS", [Net::IMAP::DELETED]) if options[:delete_after_find] && new_message.is_marked_for_delete?
|
94
100
|
break unless options[:uid].nil?
|
95
101
|
end
|
@@ -115,6 +121,7 @@ module Mail
|
|
115
121
|
mailbox = Net::IMAP.encode_utf7(mailbox)
|
116
122
|
|
117
123
|
start do |imap|
|
124
|
+
imap.select(mailbox)
|
118
125
|
imap.uid_search(['ALL']).each do |uid|
|
119
126
|
imap.uid_store(uid, "+FLAGS", [Net::IMAP::DELETED])
|
120
127
|
end
|
@@ -153,7 +160,14 @@ module Mail
|
|
153
160
|
def start(config=Mail::Configuration.instance, &block)
|
154
161
|
raise ArgumentError.new("Mail::Retrievable#imap_start takes a block") unless block_given?
|
155
162
|
|
163
|
+
if settings[:enable_starttls] && settings[:enable_ssl]
|
164
|
+
raise ArgumentError, ":enable_starttls and :enable_ssl are mutually exclusive. Set :enable_ssl if you're on an IMAPS connection. Set :enable_starttls if you're on an IMAP connection and using STARTTLS for secure TLS upgrade."
|
165
|
+
end
|
166
|
+
|
156
167
|
imap = Net::IMAP.new(settings[:address], settings[:port], settings[:enable_ssl], nil, false)
|
168
|
+
|
169
|
+
imap.starttls if settings[:enable_starttls]
|
170
|
+
|
157
171
|
if settings[:authentication].nil?
|
158
172
|
imap.login(settings[:user_name], settings[:password])
|
159
173
|
else
|