mail 2.7.1 → 2.9.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 +4 -4
- data/README.md +135 -59
- data/lib/mail/attachments_list.rb +5 -6
- data/lib/mail/body.rb +51 -74
- data/lib/mail/constants.rb +27 -5
- data/lib/mail/elements/address.rb +27 -27
- data/lib/mail/elements/address_list.rb +1 -1
- data/lib/mail/elements/content_disposition_element.rb +1 -1
- data/lib/mail/elements/content_location_element.rb +1 -1
- data/lib/mail/elements/content_transfer_encoding_element.rb +1 -1
- data/lib/mail/elements/content_type_element.rb +8 -4
- data/lib/mail/elements/date_time_element.rb +1 -1
- data/lib/mail/elements/envelope_from_element.rb +13 -7
- data/lib/mail/elements/message_ids_element.rb +14 -5
- data/lib/mail/elements/mime_version_element.rb +1 -1
- data/lib/mail/elements/phrase_list.rb +7 -2
- data/lib/mail/elements/received_element.rb +20 -6
- data/lib/mail/encodings/7bit.rb +5 -0
- data/lib/mail/encodings/base64.rb +2 -2
- data/lib/mail/encodings/quoted_printable.rb +2 -2
- data/lib/mail/encodings/unix_to_unix.rb +1 -1
- data/lib/mail/encodings.rb +32 -61
- data/lib/mail/envelope.rb +11 -14
- data/lib/mail/field.rb +100 -86
- data/lib/mail/field_list.rb +61 -8
- data/lib/mail/fields/bcc_field.rb +33 -52
- data/lib/mail/fields/cc_field.rb +27 -49
- data/lib/mail/fields/comments_field.rb +26 -37
- data/lib/mail/fields/common_address_field.rb +162 -0
- data/lib/mail/fields/common_date_field.rb +56 -0
- data/lib/mail/fields/common_field.rb +77 -0
- data/lib/mail/fields/common_message_id_field.rb +41 -0
- data/lib/mail/fields/content_description_field.rb +6 -14
- data/lib/mail/fields/content_disposition_field.rb +11 -38
- data/lib/mail/fields/content_id_field.rb +23 -51
- data/lib/mail/fields/content_location_field.rb +10 -25
- data/lib/mail/fields/content_transfer_encoding_field.rb +30 -31
- data/lib/mail/fields/content_type_field.rb +49 -75
- data/lib/mail/fields/date_field.rb +22 -51
- data/lib/mail/fields/from_field.rb +27 -49
- data/lib/mail/fields/in_reply_to_field.rb +37 -49
- data/lib/mail/fields/keywords_field.rb +17 -31
- data/lib/mail/fields/message_id_field.rb +24 -71
- data/lib/mail/fields/mime_version_field.rb +18 -30
- data/lib/mail/fields/named_structured_field.rb +10 -0
- data/lib/mail/fields/named_unstructured_field.rb +10 -0
- data/lib/mail/fields/optional_field.rb +5 -7
- data/lib/mail/fields/{common/parameter_hash.rb → parameter_hash.rb} +12 -10
- data/lib/mail/fields/received_field.rb +42 -57
- data/lib/mail/fields/references_field.rb +34 -49
- data/lib/mail/fields/reply_to_field.rb +27 -49
- data/lib/mail/fields/resent_bcc_field.rb +27 -49
- data/lib/mail/fields/resent_cc_field.rb +27 -49
- data/lib/mail/fields/resent_date_field.rb +4 -29
- data/lib/mail/fields/resent_from_field.rb +27 -49
- data/lib/mail/fields/resent_message_id_field.rb +4 -29
- data/lib/mail/fields/resent_sender_field.rb +26 -56
- data/lib/mail/fields/resent_to_field.rb +27 -49
- data/lib/mail/fields/return_path_field.rb +49 -54
- data/lib/mail/fields/sender_field.rb +33 -55
- data/lib/mail/fields/structured_field.rb +2 -30
- data/lib/mail/fields/subject_field.rb +8 -11
- data/lib/mail/fields/to_field.rb +27 -49
- data/lib/mail/fields/unstructured_field.rb +15 -48
- data/lib/mail/fields.rb +9 -0
- data/lib/mail/header.rb +69 -110
- data/lib/mail/mail.rb +32 -27
- data/lib/mail/matchers/attachment_matchers.rb +15 -0
- data/lib/mail/message.rb +67 -78
- data/lib/mail/multibyte/chars.rb +9 -167
- data/lib/mail/multibyte/unicode.rb +1 -1
- data/lib/mail/multibyte/utils.rb +26 -43
- data/lib/mail/multibyte.rb +1 -11
- data/lib/mail/network/delivery_methods/exim.rb +5 -4
- data/lib/mail/network/delivery_methods/file_delivery.rb +13 -12
- data/lib/mail/network/delivery_methods/logger_delivery.rb +2 -5
- data/lib/mail/network/delivery_methods/sendmail.rb +27 -35
- data/lib/mail/network/delivery_methods/smtp.rb +81 -30
- data/lib/mail/network/delivery_methods/smtp_connection.rb +10 -19
- data/lib/mail/network/delivery_methods/test_mailer.rb +8 -6
- data/lib/mail/network/retriever_methods/base.rb +13 -13
- data/lib/mail/network/retriever_methods/imap.rb +8 -5
- data/lib/mail/network/retriever_methods/pop3.rb +22 -22
- data/lib/mail/network/retriever_methods/test_retriever.rb +2 -1
- data/lib/mail/parsers/address_lists_parser.rb +33073 -33064
- data/lib/mail/parsers/address_lists_parser.rl +11 -0
- data/lib/mail/parsers/content_disposition_parser.rb +837 -828
- data/lib/mail/parsers/content_disposition_parser.rl +11 -0
- data/lib/mail/parsers/content_location_parser.rb +773 -764
- data/lib/mail/parsers/content_location_parser.rl +12 -1
- data/lib/mail/parsers/content_transfer_encoding_parser.rb +477 -468
- data/lib/mail/parsers/content_transfer_encoding_parser.rl +11 -0
- data/lib/mail/parsers/content_type_parser.rb +974 -965
- data/lib/mail/parsers/content_type_parser.rl +11 -0
- data/lib/mail/parsers/date_time_parser.rb +841 -832
- data/lib/mail/parsers/date_time_parser.rl +11 -0
- data/lib/mail/parsers/envelope_from_parser.rb +3627 -3530
- data/lib/mail/parsers/envelope_from_parser.rl +11 -0
- data/lib/mail/parsers/message_ids_parser.rb +5110 -2800
- data/lib/mail/parsers/message_ids_parser.rl +16 -1
- data/lib/mail/parsers/mime_version_parser.rb +466 -457
- data/lib/mail/parsers/mime_version_parser.rl +11 -0
- data/lib/mail/parsers/phrase_lists_parser.rb +839 -830
- data/lib/mail/parsers/phrase_lists_parser.rl +12 -1
- data/lib/mail/parsers/received_parser.rb +8692 -8683
- data/lib/mail/parsers/received_parser.rl +11 -0
- data/lib/mail/parsers/rfc5322.rl +28 -13
- data/lib/mail/parsers.rb +11 -17
- data/lib/mail/part.rb +24 -28
- data/lib/mail/parts_list.rb +57 -0
- data/lib/mail/smtp_envelope.rb +57 -0
- data/lib/mail/utilities.rb +321 -69
- data/lib/mail/version.rb +1 -1
- data/lib/mail/yaml.rb +30 -0
- data/lib/mail.rb +2 -22
- metadata +83 -19
- data/lib/mail/check_delivery_params.rb +0 -60
- data/lib/mail/core_extensions/smtp.rb +0 -28
- data/lib/mail/core_extensions/string.rb +0 -17
- data/lib/mail/fields/common/address_container.rb +0 -17
- data/lib/mail/fields/common/common_address.rb +0 -161
- data/lib/mail/fields/common/common_date.rb +0 -36
- data/lib/mail/fields/common/common_field.rb +0 -52
- data/lib/mail/fields/common/common_message_id.rb +0 -49
- data/lib/mail/version_specific/ruby_1_8.rb +0 -163
- data/lib/mail/version_specific/ruby_1_9.rb +0 -278
data/lib/mail/multibyte/utils.rb
CHANGED
|
@@ -3,59 +3,42 @@
|
|
|
3
3
|
|
|
4
4
|
module Mail #:nodoc:
|
|
5
5
|
module Multibyte #:nodoc:
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
VALID_CHARACTER[Encoding.default_external.to_s]
|
|
10
|
-
end
|
|
11
|
-
else
|
|
12
|
-
def self.valid_character
|
|
13
|
-
case $KCODE
|
|
14
|
-
when 'UTF8'
|
|
15
|
-
VALID_CHARACTER['UTF-8']
|
|
16
|
-
when 'SJIS'
|
|
17
|
-
VALID_CHARACTER['Shift_JIS']
|
|
18
|
-
end
|
|
19
|
-
end
|
|
6
|
+
# Returns a regular expression that matches valid characters in the current encoding
|
|
7
|
+
def self.valid_character
|
|
8
|
+
VALID_CHARACTER[Encoding.default_external.to_s]
|
|
20
9
|
end
|
|
21
10
|
|
|
22
|
-
if
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
string.split(//).all? { |c| expression =~ c }
|
|
32
|
-
else
|
|
33
|
-
true
|
|
34
|
-
end
|
|
11
|
+
# Returns true if string has valid utf-8 encoding
|
|
12
|
+
def self.is_utf8?(string)
|
|
13
|
+
case string.encoding
|
|
14
|
+
when Encoding::UTF_8
|
|
15
|
+
verify(string)
|
|
16
|
+
when Encoding::ASCII_8BIT, Encoding::US_ASCII
|
|
17
|
+
verify(to_utf8(string))
|
|
18
|
+
else
|
|
19
|
+
false
|
|
35
20
|
end
|
|
36
21
|
end
|
|
37
22
|
|
|
23
|
+
# Verifies the encoding of a string
|
|
24
|
+
def self.verify(string)
|
|
25
|
+
string.valid_encoding?
|
|
26
|
+
end
|
|
27
|
+
|
|
38
28
|
# Verifies the encoding of the string and raises an exception when it's not valid
|
|
39
29
|
def self.verify!(string)
|
|
40
30
|
raise EncodingError.new("Found characters with invalid encoding") unless verify(string)
|
|
41
31
|
end
|
|
42
32
|
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
if expression = valid_character
|
|
53
|
-
# Splits the string on character boundaries, which are determined based on $KCODE.
|
|
54
|
-
string.split(//).grep(expression).join
|
|
55
|
-
else
|
|
56
|
-
string
|
|
57
|
-
end
|
|
58
|
-
end
|
|
33
|
+
# Removes all invalid characters from the string.
|
|
34
|
+
#
|
|
35
|
+
# Note: this method is a no-op in Ruby 1.9
|
|
36
|
+
def self.clean(string)
|
|
37
|
+
string
|
|
38
|
+
end
|
|
39
|
+
|
|
40
|
+
def self.to_utf8(string)
|
|
41
|
+
string.dup.force_encoding(Encoding::UTF_8)
|
|
59
42
|
end
|
|
60
43
|
end
|
|
61
44
|
end
|
data/lib/mail/multibyte.rb
CHANGED
|
@@ -19,7 +19,6 @@ module Mail #:nodoc:
|
|
|
19
19
|
|
|
20
20
|
self.proxy_class = Mail::Multibyte::Chars
|
|
21
21
|
|
|
22
|
-
if RUBY_VERSION >= "1.9"
|
|
23
22
|
# == Multibyte proxy
|
|
24
23
|
#
|
|
25
24
|
# +mb_chars+ is a multibyte safe proxy for string methods.
|
|
@@ -54,21 +53,12 @@ module Mail #:nodoc:
|
|
|
54
53
|
# For more information about the methods defined on the Chars proxy see Mail::Multibyte::Chars. For
|
|
55
54
|
# information about how to change the default Multibyte behaviour see Mail::Multibyte.
|
|
56
55
|
def self.mb_chars(str)
|
|
57
|
-
if
|
|
56
|
+
if is_utf8?(str)
|
|
58
57
|
proxy_class.new(str)
|
|
59
58
|
else
|
|
60
59
|
str
|
|
61
60
|
end
|
|
62
61
|
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
|
|
71
|
-
end
|
|
72
62
|
|
|
73
63
|
# Regular expressions that describe valid byte sequences for a character
|
|
74
64
|
VALID_CHARACTER = {
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
# frozen_string_literal: true
|
|
2
|
-
module Mail
|
|
3
2
|
|
|
3
|
+
module Mail
|
|
4
4
|
# A delivery method implementation which sends via exim.
|
|
5
5
|
#
|
|
6
6
|
# To use this, first find out where the exim binary is on your computer,
|
|
@@ -39,11 +39,12 @@ module Mail
|
|
|
39
39
|
class Exim < Sendmail
|
|
40
40
|
DEFAULTS = {
|
|
41
41
|
:location => '/usr/sbin/exim',
|
|
42
|
-
:arguments =>
|
|
42
|
+
:arguments => %w[ -i -t ]
|
|
43
43
|
}
|
|
44
44
|
|
|
45
|
-
|
|
46
|
-
|
|
45
|
+
# Uses -t option to extract recipients from the message.
|
|
46
|
+
def destinations_for(envelope)
|
|
47
|
+
nil
|
|
47
48
|
end
|
|
48
49
|
end
|
|
49
50
|
end
|
|
@@ -1,32 +1,28 @@
|
|
|
1
1
|
# frozen_string_literal: true
|
|
2
|
-
require 'mail/
|
|
2
|
+
require 'mail/smtp_envelope'
|
|
3
3
|
|
|
4
4
|
module Mail
|
|
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
|
+
#
|
|
8
8
|
# So if you have an email going to fred@test, bob@test, joe@anothertest, and you
|
|
9
9
|
# set your location path to /path/to/mails then FileDelivery will create the directory
|
|
10
10
|
# if it does not exist, and put one copy of the email in three files, called
|
|
11
11
|
# by their message id
|
|
12
|
-
#
|
|
12
|
+
#
|
|
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
|
-
|
|
17
|
-
require 'fileutils'
|
|
18
|
-
else
|
|
19
|
-
require 'ftools'
|
|
20
|
-
end
|
|
16
|
+
require 'fileutils'
|
|
21
17
|
|
|
22
18
|
attr_accessor :settings
|
|
23
19
|
|
|
24
20
|
def initialize(values)
|
|
25
|
-
self.settings = { :location => './mails' }.merge!(values)
|
|
21
|
+
self.settings = { :location => './mails', :extension => '' }.merge!(values)
|
|
26
22
|
end
|
|
27
23
|
|
|
28
24
|
def deliver!(mail)
|
|
29
|
-
Mail::
|
|
25
|
+
envelope = Mail::SmtpEnvelope.new(mail)
|
|
30
26
|
|
|
31
27
|
if ::File.respond_to?(:makedirs)
|
|
32
28
|
::File.makedirs settings[:location]
|
|
@@ -34,8 +30,13 @@ module Mail
|
|
|
34
30
|
::FileUtils.mkdir_p settings[:location]
|
|
35
31
|
end
|
|
36
32
|
|
|
37
|
-
|
|
38
|
-
::File.
|
|
33
|
+
envelope.to.uniq.each do |to|
|
|
34
|
+
path = ::File.join(settings[:location], File.basename(to.to_s+settings[:extension]))
|
|
35
|
+
|
|
36
|
+
::File.open(path, 'a') do |f|
|
|
37
|
+
f.write envelope.message
|
|
38
|
+
f.write "\r\n\r\n"
|
|
39
|
+
end
|
|
39
40
|
end
|
|
40
41
|
end
|
|
41
42
|
end
|
|
@@ -1,9 +1,7 @@
|
|
|
1
|
-
require 'mail/
|
|
1
|
+
require 'mail/smtp_envelope'
|
|
2
2
|
|
|
3
3
|
module Mail
|
|
4
4
|
class LoggerDelivery
|
|
5
|
-
include Mail::CheckDeliveryParams
|
|
6
|
-
|
|
7
5
|
attr_reader :logger, :severity, :settings
|
|
8
6
|
|
|
9
7
|
def initialize(settings)
|
|
@@ -13,8 +11,7 @@ module Mail
|
|
|
13
11
|
end
|
|
14
12
|
|
|
15
13
|
def deliver!(mail)
|
|
16
|
-
Mail::
|
|
17
|
-
logger.log(severity) { mail.encoded }
|
|
14
|
+
logger.log(severity) { Mail::SmtpEnvelope.new(mail).message }
|
|
18
15
|
end
|
|
19
16
|
|
|
20
17
|
private
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
# frozen_string_literal: true
|
|
2
|
-
require 'mail/
|
|
2
|
+
require 'mail/smtp_envelope'
|
|
3
3
|
|
|
4
4
|
module Mail
|
|
5
5
|
# A delivery method implementation which sends via sendmail.
|
|
@@ -40,56 +40,48 @@ module Mail
|
|
|
40
40
|
class Sendmail
|
|
41
41
|
DEFAULTS = {
|
|
42
42
|
:location => '/usr/sbin/sendmail',
|
|
43
|
-
:arguments =>
|
|
43
|
+
:arguments => %w[ -i ]
|
|
44
44
|
}
|
|
45
45
|
|
|
46
46
|
attr_accessor :settings
|
|
47
47
|
|
|
48
|
+
class DeliveryError < StandardError
|
|
49
|
+
end
|
|
50
|
+
|
|
48
51
|
def initialize(values)
|
|
49
52
|
self.settings = self.class::DEFAULTS.merge(values)
|
|
53
|
+
raise ArgumentError, ":arguments expected to be an Array of individual string args" if settings[:arguments].is_a?(String)
|
|
54
|
+
end
|
|
55
|
+
|
|
56
|
+
def destinations_for(envelope)
|
|
57
|
+
envelope.to
|
|
50
58
|
end
|
|
51
59
|
|
|
52
60
|
def deliver!(mail)
|
|
53
|
-
|
|
61
|
+
envelope = Mail::SmtpEnvelope.new(mail)
|
|
54
62
|
|
|
55
|
-
|
|
56
|
-
|
|
63
|
+
command = [settings[:location]]
|
|
64
|
+
command.concat Array(settings[:arguments])
|
|
65
|
+
command.concat [ '-f', envelope.from ] if envelope.from
|
|
57
66
|
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
67
|
+
if destinations = destinations_for(envelope)
|
|
68
|
+
command.push '--'
|
|
69
|
+
command.concat destinations
|
|
70
|
+
end
|
|
61
71
|
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
io.puts ::Mail::Utilities.binary_unsafe_to_lf(encoded_message)
|
|
72
|
+
popen(command) do |io|
|
|
73
|
+
io.puts ::Mail::Utilities.binary_unsafe_to_lf(envelope.message)
|
|
65
74
|
io.flush
|
|
66
75
|
end
|
|
67
76
|
end
|
|
68
77
|
|
|
69
|
-
|
|
70
|
-
def
|
|
71
|
-
IO.popen
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
78
|
+
private
|
|
79
|
+
def popen(command, &block)
|
|
80
|
+
IO.popen(command, 'w+', :err => :out, &block).tap do
|
|
81
|
+
if $?.exitstatus != 0
|
|
82
|
+
raise DeliveryError, "Delivery failed with exitstatus #{$?.exitstatus}: #{command.inspect}"
|
|
83
|
+
end
|
|
84
|
+
end
|
|
76
85
|
end
|
|
77
|
-
end
|
|
78
|
-
|
|
79
|
-
# The following is an adaptation of ruby 1.9.2's shellwords.rb file,
|
|
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
|
|
85
|
-
def self.shellquote(address)
|
|
86
|
-
# Process as a single byte sequence because not all shell
|
|
87
|
-
# implementations are multibyte aware.
|
|
88
|
-
#
|
|
89
|
-
# A LF cannot be escaped with a backslash because a backslash + LF
|
|
90
|
-
# combo is regarded as line continuation and simply ignored. Strip it.
|
|
91
|
-
escaped = address.gsub(/([^A-Za-z0-9_\s\+\-.,:\/@~])/n, "\\\\\\1").gsub("\n", '')
|
|
92
|
-
%("#{escaped}")
|
|
93
|
-
end
|
|
94
86
|
end
|
|
95
87
|
end
|
|
@@ -1,20 +1,20 @@
|
|
|
1
1
|
# frozen_string_literal: true
|
|
2
|
-
require 'mail/
|
|
2
|
+
require 'mail/smtp_envelope'
|
|
3
3
|
|
|
4
4
|
module Mail
|
|
5
5
|
# == Sending Email with SMTP
|
|
6
|
-
#
|
|
6
|
+
#
|
|
7
7
|
# Mail allows you to send emails using SMTP. This is done by wrapping Net::SMTP in
|
|
8
8
|
# an easy to use manner.
|
|
9
|
-
#
|
|
9
|
+
#
|
|
10
10
|
# === Sending via SMTP server on Localhost
|
|
11
|
-
#
|
|
11
|
+
#
|
|
12
12
|
# Sending locally (to a postfix or sendmail server running on localhost) requires
|
|
13
13
|
# no special setup. Just to Mail.deliver &block or message.deliver! and it will
|
|
14
14
|
# be sent in this method.
|
|
15
|
-
#
|
|
15
|
+
#
|
|
16
16
|
# === Sending via MobileMe
|
|
17
|
-
#
|
|
17
|
+
#
|
|
18
18
|
# Mail.defaults do
|
|
19
19
|
# delivery_method :smtp, { :address => "smtp.me.com",
|
|
20
20
|
# :port => 587,
|
|
@@ -22,11 +22,11 @@ module Mail
|
|
|
22
22
|
# :user_name => '<username>',
|
|
23
23
|
# :password => '<password>',
|
|
24
24
|
# :authentication => 'plain',
|
|
25
|
-
# :
|
|
25
|
+
# :enable_starttls => :auto }
|
|
26
26
|
# end
|
|
27
|
-
#
|
|
27
|
+
#
|
|
28
28
|
# === Sending via GMail
|
|
29
|
-
#
|
|
29
|
+
#
|
|
30
30
|
# Mail.defaults do
|
|
31
31
|
# delivery_method :smtp, { :address => "smtp.gmail.com",
|
|
32
32
|
# :port => 587,
|
|
@@ -34,9 +34,17 @@ module Mail
|
|
|
34
34
|
# :user_name => '<username>',
|
|
35
35
|
# :password => '<password>',
|
|
36
36
|
# :authentication => 'plain',
|
|
37
|
-
# :
|
|
37
|
+
# :enable_starttls => :auto }
|
|
38
38
|
# end
|
|
39
39
|
#
|
|
40
|
+
# === Configuring TLS/SSL and STARTTLS
|
|
41
|
+
#
|
|
42
|
+
# A few remarks:
|
|
43
|
+
# - when enabling `tls` (or `ssl`), setting (truthy values for) either `enable_starttls` or `enable_starttls_auto` will raise an ArgumentError as TLS and STARTTLS are mutually exclusive.
|
|
44
|
+
# - to configure STARTTLS, use the `enable_starttls`-flag (instead of a combination of `enable_starttls` and `enable_starttls_auto`). Acceptable values are `:always`, `:auto` and `false`.
|
|
45
|
+
# - when providing a truthy value for `enable_starttls`, the `enable_starttls_auto`-flag will be ignored.
|
|
46
|
+
# - when none of `tls`, `ssl`, `enable_starttls` or `enable_starttls_auto` is set, the fallback will be `enable_starttls` `:auto`.
|
|
47
|
+
#
|
|
40
48
|
# === Certificate verification
|
|
41
49
|
#
|
|
42
50
|
# When using TLS, some mail servers provide certificates that are self-signed
|
|
@@ -48,30 +56,30 @@ module Mail
|
|
|
48
56
|
# verify mode constant (OpenSSL::SSL::VERIFY_NONE, OpenSSL::SSL::VERIFY_PEER),
|
|
49
57
|
# or a string containing the name of an OpenSSL verify mode (none, peer).
|
|
50
58
|
#
|
|
51
|
-
# === Others
|
|
52
|
-
#
|
|
59
|
+
# === Others
|
|
60
|
+
#
|
|
53
61
|
# Feel free to send me other examples that were tricky
|
|
54
|
-
#
|
|
62
|
+
#
|
|
55
63
|
# === Delivering the email
|
|
56
|
-
#
|
|
64
|
+
#
|
|
57
65
|
# Once you have the settings right, sending the email is done by:
|
|
58
|
-
#
|
|
66
|
+
#
|
|
59
67
|
# Mail.deliver do
|
|
60
68
|
# to 'mikel@test.lindsaar.net'
|
|
61
69
|
# from 'ada@test.lindsaar.net'
|
|
62
70
|
# subject 'testing sendmail'
|
|
63
71
|
# body 'testing sendmail'
|
|
64
72
|
# end
|
|
65
|
-
#
|
|
73
|
+
#
|
|
66
74
|
# Or by calling deliver on a Mail message
|
|
67
|
-
#
|
|
75
|
+
#
|
|
68
76
|
# mail = Mail.new do
|
|
69
77
|
# to 'mikel@test.lindsaar.net'
|
|
70
78
|
# from 'ada@test.lindsaar.net'
|
|
71
79
|
# subject 'testing sendmail'
|
|
72
80
|
# body 'testing sendmail'
|
|
73
81
|
# end
|
|
74
|
-
#
|
|
82
|
+
#
|
|
75
83
|
# mail.deliver!
|
|
76
84
|
class SMTP
|
|
77
85
|
attr_accessor :settings
|
|
@@ -84,12 +92,12 @@ module Mail
|
|
|
84
92
|
:password => nil,
|
|
85
93
|
:authentication => nil,
|
|
86
94
|
:enable_starttls => nil,
|
|
87
|
-
:enable_starttls_auto =>
|
|
95
|
+
:enable_starttls_auto => nil,
|
|
88
96
|
:openssl_verify_mode => nil,
|
|
89
97
|
:ssl => nil,
|
|
90
98
|
:tls => nil,
|
|
91
|
-
:open_timeout =>
|
|
92
|
-
:read_timeout =>
|
|
99
|
+
:open_timeout => 5,
|
|
100
|
+
:read_timeout => 5
|
|
93
101
|
}
|
|
94
102
|
|
|
95
103
|
def initialize(values)
|
|
@@ -105,23 +113,66 @@ module Mail
|
|
|
105
113
|
end
|
|
106
114
|
|
|
107
115
|
private
|
|
116
|
+
# `k` is said to be provided when `settings` has a non-nil value for `k`.
|
|
117
|
+
def setting_provided?(k)
|
|
118
|
+
!settings[k].nil?
|
|
119
|
+
end
|
|
120
|
+
|
|
121
|
+
# Yields one of `:always`, `:auto` or `false` based on `enable_starttls` and `enable_starttls_auto` flags.
|
|
122
|
+
# Yields `false` when `smtp_tls?`.
|
|
123
|
+
# Else defaults to `:auto` when neither `enable_starttls*` flag is provided.
|
|
124
|
+
# Providing a truthy value for `enable_starttls` will ignore `enable_starttls_auto`.
|
|
125
|
+
def smtp_starttls
|
|
126
|
+
return false if smtp_tls?
|
|
127
|
+
|
|
128
|
+
if setting_provided?(:enable_starttls) && settings[:enable_starttls]
|
|
129
|
+
# enable_starttls: provided and truthy
|
|
130
|
+
case settings[:enable_starttls]
|
|
131
|
+
when :auto then :auto
|
|
132
|
+
when :always then :always
|
|
133
|
+
else
|
|
134
|
+
:always
|
|
135
|
+
end
|
|
136
|
+
else
|
|
137
|
+
# enable_starttls: not provided or false
|
|
138
|
+
if setting_provided?(:enable_starttls_auto)
|
|
139
|
+
settings[:enable_starttls_auto] ? :auto : false
|
|
140
|
+
else
|
|
141
|
+
# enable_starttls_auto: not provided
|
|
142
|
+
# enable_starttls: when provided then false
|
|
143
|
+
# use :auto when neither enable_starttls* provided
|
|
144
|
+
setting_provided?(:enable_starttls) ? false : :auto
|
|
145
|
+
end
|
|
146
|
+
end
|
|
147
|
+
end
|
|
148
|
+
|
|
149
|
+
def smtp_tls?
|
|
150
|
+
(setting_provided?(:tls) && settings[:tls]) || (setting_provided?(:ssl) && settings[:ssl])
|
|
151
|
+
end
|
|
152
|
+
|
|
108
153
|
def start_smtp_session(&block)
|
|
109
154
|
build_smtp_session.start(settings[:domain], settings[:user_name], settings[:password], settings[:authentication], &block)
|
|
110
155
|
end
|
|
111
156
|
|
|
112
157
|
def build_smtp_session
|
|
158
|
+
if smtp_tls? && (settings[:enable_starttls] || settings[:enable_starttls_auto])
|
|
159
|
+
raise ArgumentError, ":enable_starttls and :tls are mutually exclusive. Set :tls if you're on an SMTPS connection. Set :enable_starttls if you're on an SMTP connection and using STARTTLS for secure TLS upgrade."
|
|
160
|
+
end
|
|
161
|
+
|
|
113
162
|
Net::SMTP.new(settings[:address], settings[:port]).tap do |smtp|
|
|
114
|
-
if
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
163
|
+
if smtp_tls?
|
|
164
|
+
smtp.disable_starttls
|
|
165
|
+
smtp.enable_tls(ssl_context)
|
|
166
|
+
else
|
|
167
|
+
smtp.disable_tls
|
|
168
|
+
|
|
169
|
+
case smtp_starttls
|
|
170
|
+
when :always
|
|
120
171
|
smtp.enable_starttls(ssl_context)
|
|
121
|
-
|
|
122
|
-
elsif settings[:enable_starttls_auto]
|
|
123
|
-
if smtp.respond_to?(:enable_starttls_auto)
|
|
172
|
+
when :auto
|
|
124
173
|
smtp.enable_starttls_auto(ssl_context)
|
|
174
|
+
else
|
|
175
|
+
smtp.disable_starttls
|
|
125
176
|
end
|
|
126
177
|
end
|
|
127
178
|
|
|
@@ -1,41 +1,41 @@
|
|
|
1
1
|
# frozen_string_literal: true
|
|
2
|
-
require 'mail/
|
|
2
|
+
require 'mail/smtp_envelope'
|
|
3
3
|
|
|
4
4
|
module Mail
|
|
5
5
|
# == Sending Email with SMTP
|
|
6
|
-
#
|
|
6
|
+
#
|
|
7
7
|
# Mail allows you to send emails using an open SMTP connection. This is done by
|
|
8
8
|
# passing a created Net::SMTP object. This way we can get better performance to
|
|
9
9
|
# our local mail server by reducing the number of connections at any one time.
|
|
10
10
|
#
|
|
11
11
|
# === Sending via SMTP server on Localhost
|
|
12
|
-
#
|
|
12
|
+
#
|
|
13
13
|
# To send mail open a connection with Net::Smtp using any options you like
|
|
14
14
|
# === Delivering the email
|
|
15
|
-
#
|
|
15
|
+
#
|
|
16
16
|
# Once you have the settings right, sending the email is done by:
|
|
17
17
|
#
|
|
18
18
|
# smtp_conn = Net::SMTP.start(settings[:address], settings[:port])
|
|
19
19
|
# Mail.defaults do
|
|
20
20
|
# delivery_method :smtp_connection, { :connection => smtp_conn }
|
|
21
21
|
# end
|
|
22
|
-
#
|
|
22
|
+
#
|
|
23
23
|
# Mail.deliver do
|
|
24
24
|
# to 'mikel@test.lindsaar.net'
|
|
25
25
|
# from 'ada@test.lindsaar.net'
|
|
26
26
|
# subject 'testing sendmail'
|
|
27
27
|
# body 'testing sendmail'
|
|
28
28
|
# end
|
|
29
|
-
#
|
|
29
|
+
#
|
|
30
30
|
# Or by calling deliver on a Mail message
|
|
31
|
-
#
|
|
31
|
+
#
|
|
32
32
|
# mail = Mail.new do
|
|
33
33
|
# to 'mikel@test.lindsaar.net'
|
|
34
34
|
# from 'ada@test.lindsaar.net'
|
|
35
35
|
# subject 'testing sendmail'
|
|
36
36
|
# body 'testing sendmail'
|
|
37
37
|
# end
|
|
38
|
-
#
|
|
38
|
+
#
|
|
39
39
|
# mail.deliver!
|
|
40
40
|
class SMTPConnection
|
|
41
41
|
attr_accessor :smtp, :settings
|
|
@@ -49,18 +49,9 @@ module Mail
|
|
|
49
49
|
# Send the message via SMTP.
|
|
50
50
|
# The from and to attributes are optional. If not set, they are retrieve from the Message.
|
|
51
51
|
def deliver!(mail)
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
response = smtp.sendmail(dot_stuff(message), smtp_from, smtp_to)
|
|
55
|
-
|
|
52
|
+
envelope = Mail::SmtpEnvelope.new(mail)
|
|
53
|
+
response = smtp.sendmail(envelope.message, envelope.from, envelope.to)
|
|
56
54
|
settings[:return_response] ? response : self
|
|
57
55
|
end
|
|
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
|
|
65
56
|
end
|
|
66
57
|
end
|
|
@@ -1,10 +1,10 @@
|
|
|
1
1
|
# frozen_string_literal: true
|
|
2
|
-
require 'mail/
|
|
2
|
+
require 'mail/smtp_envelope'
|
|
3
3
|
|
|
4
4
|
module Mail
|
|
5
5
|
# The TestMailer is a bare bones mailer that does nothing. It is useful
|
|
6
6
|
# when you are testing.
|
|
7
|
-
#
|
|
7
|
+
#
|
|
8
8
|
# It also provides a template of the minimum methods you require to implement
|
|
9
9
|
# if you want to make a custom mailer for Mail
|
|
10
10
|
class TestMailer
|
|
@@ -14,11 +14,11 @@ module Mail
|
|
|
14
14
|
end
|
|
15
15
|
|
|
16
16
|
# Allows you to over write the default deliveries store from an array to some
|
|
17
|
-
# other object. If you just want to clear the store,
|
|
17
|
+
# other object. If you just want to clear the store,
|
|
18
18
|
# call TestMailer.deliveries.clear.
|
|
19
|
-
#
|
|
19
|
+
#
|
|
20
20
|
# If you place another object here, please make sure it responds to:
|
|
21
|
-
#
|
|
21
|
+
#
|
|
22
22
|
# * << (message)
|
|
23
23
|
# * clear
|
|
24
24
|
# * length
|
|
@@ -35,7 +35,9 @@ module Mail
|
|
|
35
35
|
end
|
|
36
36
|
|
|
37
37
|
def deliver!(mail)
|
|
38
|
-
|
|
38
|
+
# Create the envelope to validate it
|
|
39
|
+
Mail::SmtpEnvelope.new(mail)
|
|
40
|
+
|
|
39
41
|
Mail::TestMailer.deliveries << mail
|
|
40
42
|
end
|
|
41
43
|
end
|
|
@@ -11,38 +11,38 @@ module Mail
|
|
|
11
11
|
# count: number of emails to retrieve. The default value is 1.
|
|
12
12
|
# order: order of emails returned. Possible values are :asc or :desc. Default value is :asc.
|
|
13
13
|
#
|
|
14
|
-
def first(options =
|
|
15
|
-
options
|
|
14
|
+
def first(options = nil, &block)
|
|
15
|
+
options = options ? Hash[options] : {}
|
|
16
16
|
options[:what] = :first
|
|
17
17
|
options[:count] ||= 1
|
|
18
18
|
find(options, &block)
|
|
19
19
|
end
|
|
20
|
-
|
|
20
|
+
|
|
21
21
|
# Get the most recent received email(s)
|
|
22
22
|
#
|
|
23
23
|
# Possible options:
|
|
24
24
|
# count: number of emails to retrieve. The default value is 1.
|
|
25
25
|
# order: order of emails returned. Possible values are :asc or :desc. Default value is :asc.
|
|
26
26
|
#
|
|
27
|
-
def last(options =
|
|
28
|
-
options
|
|
27
|
+
def last(options = nil, &block)
|
|
28
|
+
options = options ? Hash[options] : {}
|
|
29
29
|
options[:what] = :last
|
|
30
30
|
options[:count] ||= 1
|
|
31
31
|
find(options, &block)
|
|
32
32
|
end
|
|
33
|
-
|
|
33
|
+
|
|
34
34
|
# Get all emails.
|
|
35
35
|
#
|
|
36
36
|
# Possible options:
|
|
37
37
|
# order: order of emails returned. Possible values are :asc or :desc. Default value is :asc.
|
|
38
38
|
#
|
|
39
|
-
def all(options =
|
|
40
|
-
options
|
|
39
|
+
def all(options = nil, &block)
|
|
40
|
+
options = options ? Hash[options] : {}
|
|
41
41
|
options[:count] = :all
|
|
42
42
|
find(options, &block)
|
|
43
43
|
end
|
|
44
44
|
|
|
45
|
-
# Find emails in the mailbox, and then deletes them. Without any options, the
|
|
45
|
+
# Find emails in the mailbox, and then deletes them. Without any options, the
|
|
46
46
|
# five last received emails are returned.
|
|
47
47
|
#
|
|
48
48
|
# Possible options:
|
|
@@ -53,11 +53,11 @@ module Mail
|
|
|
53
53
|
# delete_after_find: flag for whether to delete each retreived email after find. Default
|
|
54
54
|
# is true. Call #find if you would like this to default to false.
|
|
55
55
|
#
|
|
56
|
-
def find_and_delete(options =
|
|
57
|
-
options
|
|
56
|
+
def find_and_delete(options = nil, &block)
|
|
57
|
+
options = options ? Hash[options] : {}
|
|
58
58
|
options[:delete_after_find] ||= true
|
|
59
|
-
find(options, &block)
|
|
60
|
-
end
|
|
59
|
+
find(options, &block)
|
|
60
|
+
end
|
|
61
61
|
|
|
62
62
|
end
|
|
63
63
|
|