mail 2.6.4 → 2.9.0
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/README.md +208 -156
- data/lib/mail/attachments_list.rb +13 -10
- data/lib/mail/body.rb +96 -107
- data/lib/mail/configuration.rb +2 -0
- data/lib/mail/constants.rb +27 -5
- data/lib/mail/elements/address.rb +61 -50
- data/lib/mail/elements/address_list.rb +11 -19
- data/lib/mail/elements/content_disposition_element.rb +9 -16
- data/lib/mail/elements/content_location_element.rb +6 -11
- data/lib/mail/elements/content_transfer_encoding_element.rb +6 -11
- data/lib/mail/elements/content_type_element.rb +16 -23
- data/lib/mail/elements/date_time_element.rb +7 -15
- data/lib/mail/elements/envelope_from_element.rb +22 -23
- data/lib/mail/elements/message_ids_element.rb +18 -13
- data/lib/mail/elements/mime_version_element.rb +7 -15
- data/lib/mail/elements/phrase_list.rb +12 -10
- data/lib/mail/elements/received_element.rb +27 -19
- data/lib/mail/encodings/7bit.rb +9 -14
- data/lib/mail/encodings/8bit.rb +2 -21
- data/lib/mail/encodings/base64.rb +11 -12
- data/lib/mail/encodings/binary.rb +3 -22
- data/lib/mail/encodings/identity.rb +24 -0
- data/lib/mail/encodings/quoted_printable.rb +6 -6
- data/lib/mail/encodings/transfer_encoding.rb +38 -29
- data/lib/mail/encodings/unix_to_unix.rb +4 -2
- data/lib/mail/encodings.rb +83 -56
- data/lib/mail/envelope.rb +11 -14
- data/lib/mail/field.rb +181 -130
- 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 +53 -84
- data/lib/mail/fields/date_field.rb +22 -52
- 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 +9 -8
- data/lib/mail/fields/{common/parameter_hash.rb → parameter_hash.rb} +13 -11
- 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 -30
- 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 +31 -47
- data/lib/mail/fields.rb +9 -0
- data/lib/mail/header.rb +71 -110
- data/lib/mail/mail.rb +34 -37
- data/lib/mail/matchers/attachment_matchers.rb +15 -0
- data/lib/mail/matchers/has_sent_mail.rb +21 -1
- data/lib/mail/message.rb +126 -127
- data/lib/mail/multibyte/chars.rb +24 -181
- data/lib/mail/multibyte/unicode.rb +11 -11
- data/lib/mail/multibyte/utils.rb +26 -43
- data/lib/mail/multibyte.rb +55 -16
- data/lib/mail/network/delivery_methods/exim.rb +8 -11
- data/lib/mail/network/delivery_methods/file_delivery.rb +15 -18
- data/lib/mail/network/delivery_methods/logger_delivery.rb +34 -0
- data/lib/mail/network/delivery_methods/sendmail.rb +32 -35
- data/lib/mail/network/delivery_methods/smtp.rb +125 -68
- data/lib/mail/network/delivery_methods/smtp_connection.rb +11 -16
- data/lib/mail/network/delivery_methods/test_mailer.rb +12 -13
- data/lib/mail/network/retriever_methods/base.rb +13 -13
- data/lib/mail/network/retriever_methods/imap.rb +25 -9
- data/lib/mail/network/retriever_methods/pop3.rb +25 -23
- data/lib/mail/network/retriever_methods/test_retriever.rb +3 -2
- data/lib/mail/network.rb +1 -0
- data/lib/mail/parser_tools.rb +15 -0
- data/lib/mail/parsers/address_lists_parser.rb +33228 -116
- data/lib/mail/parsers/address_lists_parser.rl +183 -0
- data/lib/mail/parsers/content_disposition_parser.rb +885 -49
- data/lib/mail/parsers/content_disposition_parser.rl +93 -0
- data/lib/mail/parsers/content_location_parser.rb +812 -23
- data/lib/mail/parsers/content_location_parser.rl +82 -0
- data/lib/mail/parsers/content_transfer_encoding_parser.rb +512 -21
- data/lib/mail/parsers/content_transfer_encoding_parser.rl +75 -0
- data/lib/mail/parsers/content_type_parser.rb +1039 -55
- data/lib/mail/parsers/content_type_parser.rl +94 -0
- data/lib/mail/parsers/date_time_parser.rb +880 -25
- data/lib/mail/parsers/date_time_parser.rl +73 -0
- data/lib/mail/parsers/envelope_from_parser.rb +3672 -40
- data/lib/mail/parsers/envelope_from_parser.rl +93 -0
- data/lib/mail/parsers/message_ids_parser.rb +5149 -25
- data/lib/mail/parsers/message_ids_parser.rl +97 -0
- data/lib/mail/parsers/mime_version_parser.rb +500 -26
- data/lib/mail/parsers/mime_version_parser.rl +72 -0
- data/lib/mail/parsers/phrase_lists_parser.rb +873 -22
- data/lib/mail/parsers/phrase_lists_parser.rl +94 -0
- data/lib/mail/parsers/received_parser.rb +8779 -43
- data/lib/mail/parsers/received_parser.rl +95 -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 +74 -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 +11 -25
- data/lib/mail/part.rb +25 -29
- data/lib/mail/parts_list.rb +62 -6
- data/lib/mail/smtp_envelope.rb +57 -0
- data/lib/mail/utilities.rb +361 -74
- data/lib/mail/version.rb +2 -2
- data/lib/mail/yaml.rb +30 -0
- data/lib/mail.rb +4 -37
- metadata +125 -67
- data/CHANGELOG.rdoc +0 -787
- data/CONTRIBUTING.md +0 -60
- data/Dependencies.txt +0 -2
- data/Gemfile +0 -11
- data/Rakefile +0 -29
- data/TODO.rdoc +0 -9
- data/lib/mail/check_delivery_params.rb +0 -21
- data/lib/mail/core_extensions/smtp.rb +0 -25
- data/lib/mail/core_extensions/string/access.rb +0 -146
- data/lib/mail/core_extensions/string/multibyte.rb +0 -79
- data/lib/mail/core_extensions/string.rb +0 -21
- data/lib/mail/fields/common/address_container.rb +0 -17
- data/lib/mail/fields/common/common_address.rb +0 -136
- data/lib/mail/fields/common/common_date.rb +0 -36
- data/lib/mail/fields/common/common_field.rb +0 -61
- data/lib/mail/fields/common/common_message_id.rb +0 -49
- data/lib/mail/multibyte/exceptions.rb +0 -9
- data/lib/mail/parsers/ragel/common.rl +0 -185
- 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 -2149
- 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 -40
- data/lib/mail/parsers/ragel.rb +0 -18
- data/lib/mail/version_specific/ruby_1_8.rb +0 -126
- data/lib/mail/version_specific/ruby_1_9.rb +0 -223
|
@@ -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.
|
|
@@ -38,53 +38,50 @@ module Mail
|
|
|
38
38
|
#
|
|
39
39
|
# mail.deliver!
|
|
40
40
|
class Sendmail
|
|
41
|
-
|
|
41
|
+
DEFAULTS = {
|
|
42
|
+
:location => '/usr/sbin/sendmail',
|
|
43
|
+
:arguments => %w[ -i ]
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
attr_accessor :settings
|
|
47
|
+
|
|
48
|
+
class DeliveryError < StandardError
|
|
49
|
+
end
|
|
42
50
|
|
|
43
51
|
def initialize(values)
|
|
44
|
-
self.settings =
|
|
45
|
-
|
|
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)
|
|
46
54
|
end
|
|
47
55
|
|
|
48
|
-
|
|
56
|
+
def destinations_for(envelope)
|
|
57
|
+
envelope.to
|
|
58
|
+
end
|
|
49
59
|
|
|
50
60
|
def deliver!(mail)
|
|
51
|
-
|
|
61
|
+
envelope = Mail::SmtpEnvelope.new(mail)
|
|
52
62
|
|
|
53
|
-
|
|
54
|
-
|
|
63
|
+
command = [settings[:location]]
|
|
64
|
+
command.concat Array(settings[:arguments])
|
|
65
|
+
command.concat [ '-f', envelope.from ] if envelope.from
|
|
55
66
|
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
67
|
+
if destinations = destinations_for(envelope)
|
|
68
|
+
command.push '--'
|
|
69
|
+
command.concat destinations
|
|
70
|
+
end
|
|
59
71
|
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
io.puts ::Mail::Utilities.to_lf(encoded_message)
|
|
72
|
+
popen(command) do |io|
|
|
73
|
+
io.puts ::Mail::Utilities.binary_unsafe_to_lf(envelope.message)
|
|
63
74
|
io.flush
|
|
64
75
|
end
|
|
65
76
|
end
|
|
66
77
|
|
|
67
|
-
|
|
68
|
-
def
|
|
69
|
-
IO.popen
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
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
|
|
74
85
|
end
|
|
75
|
-
end
|
|
76
|
-
|
|
77
|
-
# The following is an adaptation of ruby 1.9.2's shellwords.rb file,
|
|
78
|
-
# it is modified to include '+' in the allowed list to allow for
|
|
79
|
-
# sendmail to accept email addresses as the sender with a + in them.
|
|
80
|
-
def self.shellquote(address)
|
|
81
|
-
# Process as a single byte sequence because not all shell
|
|
82
|
-
# implementations are multibyte aware.
|
|
83
|
-
#
|
|
84
|
-
# A LF cannot be escaped with a backslash because a backslash + LF
|
|
85
|
-
# combo is regarded as line continuation and simply ignored. Strip it.
|
|
86
|
-
escaped = address.gsub(/([^A-Za-z0-9_\s\+\-.,:\/@])/n, "\\\\\\1").gsub("\n", '')
|
|
87
|
-
%("#{escaped}")
|
|
88
|
-
end
|
|
89
86
|
end
|
|
90
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
|
|
@@ -45,99 +53,148 @@ module Mail
|
|
|
45
53
|
# hostname or update the certificate authorities trusted by your ruby. If
|
|
46
54
|
# that isn't possible, you can control this behavior with
|
|
47
55
|
# an :openssl_verify_mode setting. Its value may be either an OpenSSL
|
|
48
|
-
# verify mode constant (OpenSSL::SSL::VERIFY_NONE),
|
|
49
|
-
# the name of an OpenSSL verify mode (none, peer
|
|
50
|
-
#
|
|
56
|
+
# verify mode constant (OpenSSL::SSL::VERIFY_NONE, OpenSSL::SSL::VERIFY_PEER),
|
|
57
|
+
# or a string containing the name of an OpenSSL verify mode (none, peer).
|
|
58
|
+
#
|
|
59
|
+
# === Others
|
|
51
60
|
#
|
|
52
|
-
# === Others
|
|
53
|
-
#
|
|
54
61
|
# Feel free to send me other examples that were tricky
|
|
55
|
-
#
|
|
62
|
+
#
|
|
56
63
|
# === Delivering the email
|
|
57
|
-
#
|
|
64
|
+
#
|
|
58
65
|
# Once you have the settings right, sending the email is done by:
|
|
59
|
-
#
|
|
66
|
+
#
|
|
60
67
|
# Mail.deliver do
|
|
61
68
|
# to 'mikel@test.lindsaar.net'
|
|
62
69
|
# from 'ada@test.lindsaar.net'
|
|
63
70
|
# subject 'testing sendmail'
|
|
64
71
|
# body 'testing sendmail'
|
|
65
72
|
# end
|
|
66
|
-
#
|
|
73
|
+
#
|
|
67
74
|
# Or by calling deliver on a Mail message
|
|
68
|
-
#
|
|
75
|
+
#
|
|
69
76
|
# mail = Mail.new do
|
|
70
77
|
# to 'mikel@test.lindsaar.net'
|
|
71
78
|
# from 'ada@test.lindsaar.net'
|
|
72
79
|
# subject 'testing sendmail'
|
|
73
80
|
# body 'testing sendmail'
|
|
74
81
|
# end
|
|
75
|
-
#
|
|
82
|
+
#
|
|
76
83
|
# mail.deliver!
|
|
77
84
|
class SMTP
|
|
78
|
-
|
|
85
|
+
attr_accessor :settings
|
|
86
|
+
|
|
87
|
+
DEFAULTS = {
|
|
88
|
+
:address => 'localhost',
|
|
89
|
+
:port => 25,
|
|
90
|
+
:domain => 'localhost.localdomain',
|
|
91
|
+
:user_name => nil,
|
|
92
|
+
:password => nil,
|
|
93
|
+
:authentication => nil,
|
|
94
|
+
:enable_starttls => nil,
|
|
95
|
+
:enable_starttls_auto => nil,
|
|
96
|
+
:openssl_verify_mode => nil,
|
|
97
|
+
:ssl => nil,
|
|
98
|
+
:tls => nil,
|
|
99
|
+
:open_timeout => 5,
|
|
100
|
+
:read_timeout => 5
|
|
101
|
+
}
|
|
79
102
|
|
|
80
103
|
def initialize(values)
|
|
81
|
-
self.settings =
|
|
82
|
-
:port => 25,
|
|
83
|
-
:domain => 'localhost.localdomain',
|
|
84
|
-
:user_name => nil,
|
|
85
|
-
:password => nil,
|
|
86
|
-
:authentication => nil,
|
|
87
|
-
:enable_starttls_auto => true,
|
|
88
|
-
:openssl_verify_mode => nil,
|
|
89
|
-
:ssl => nil,
|
|
90
|
-
:tls => nil
|
|
91
|
-
}.merge!(values)
|
|
104
|
+
self.settings = DEFAULTS.merge(values)
|
|
92
105
|
end
|
|
93
106
|
|
|
94
|
-
attr_accessor :settings
|
|
95
|
-
|
|
96
|
-
# Send the message via SMTP.
|
|
97
|
-
# The from and to attributes are optional. If not set, they are retrieve from the Message.
|
|
98
107
|
def deliver!(mail)
|
|
99
|
-
|
|
108
|
+
response = start_smtp_session do |smtp|
|
|
109
|
+
Mail::SMTPConnection.new(:connection => smtp, :return_response => true).deliver!(mail)
|
|
110
|
+
end
|
|
100
111
|
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
112
|
+
settings[:return_response] ? response : self
|
|
113
|
+
end
|
|
114
|
+
|
|
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
|
|
109
146
|
end
|
|
110
147
|
end
|
|
111
148
|
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
response = smtp_obj.sendmail(message, smtp_from, smtp_to)
|
|
149
|
+
def smtp_tls?
|
|
150
|
+
(setting_provided?(:tls) && settings[:tls]) || (setting_provided?(:ssl) && settings[:ssl])
|
|
115
151
|
end
|
|
116
152
|
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
else
|
|
120
|
-
self
|
|
153
|
+
def start_smtp_session(&block)
|
|
154
|
+
build_smtp_session.start(settings[:domain], settings[:user_name], settings[:password], settings[:authentication], &block)
|
|
121
155
|
end
|
|
122
|
-
end
|
|
123
|
-
|
|
124
156
|
|
|
125
|
-
|
|
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
|
+
|
|
162
|
+
Net::SMTP.new(settings[:address], settings[:port]).tap do |smtp|
|
|
163
|
+
if smtp_tls?
|
|
164
|
+
smtp.disable_starttls
|
|
165
|
+
smtp.enable_tls(ssl_context)
|
|
166
|
+
else
|
|
167
|
+
smtp.disable_tls
|
|
126
168
|
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
169
|
+
case smtp_starttls
|
|
170
|
+
when :always
|
|
171
|
+
smtp.enable_starttls(ssl_context)
|
|
172
|
+
when :auto
|
|
173
|
+
smtp.enable_starttls_auto(ssl_context)
|
|
174
|
+
else
|
|
175
|
+
smtp.disable_starttls
|
|
176
|
+
end
|
|
177
|
+
end
|
|
131
178
|
|
|
132
|
-
|
|
133
|
-
|
|
179
|
+
smtp.open_timeout = settings[:open_timeout] if settings[:open_timeout]
|
|
180
|
+
smtp.read_timeout = settings[:read_timeout] if settings[:read_timeout]
|
|
181
|
+
end
|
|
134
182
|
end
|
|
135
183
|
|
|
136
|
-
context
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
184
|
+
# Allow SSL context to be configured via settings, for Ruby >= 1.9
|
|
185
|
+
# Just returns openssl verify mode for Ruby 1.8.x
|
|
186
|
+
def ssl_context
|
|
187
|
+
openssl_verify_mode = settings[:openssl_verify_mode]
|
|
188
|
+
|
|
189
|
+
if openssl_verify_mode.kind_of?(String)
|
|
190
|
+
openssl_verify_mode = OpenSSL::SSL.const_get("VERIFY_#{openssl_verify_mode.upcase}")
|
|
191
|
+
end
|
|
192
|
+
|
|
193
|
+
context = Net::SMTP.default_ssl_context
|
|
194
|
+
context.verify_mode = openssl_verify_mode if openssl_verify_mode
|
|
195
|
+
context.ca_path = settings[:ca_path] if settings[:ca_path]
|
|
196
|
+
context.ca_file = settings[:ca_file] if settings[:ca_file]
|
|
197
|
+
context
|
|
198
|
+
end
|
|
142
199
|
end
|
|
143
200
|
end
|
|
@@ -1,44 +1,44 @@
|
|
|
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
|
|
42
42
|
|
|
43
43
|
def initialize(values)
|
|
44
44
|
raise ArgumentError.new('A Net::SMTP object is required for this delivery method') if values[:connection].nil?
|
|
@@ -46,17 +46,12 @@ module Mail
|
|
|
46
46
|
self.settings = values
|
|
47
47
|
end
|
|
48
48
|
|
|
49
|
-
attr_accessor :smtp
|
|
50
|
-
attr_accessor :settings
|
|
51
|
-
|
|
52
49
|
# Send the message via SMTP.
|
|
53
50
|
# The from and to attributes are optional. If not set, they are retrieve from the Message.
|
|
54
51
|
def deliver!(mail)
|
|
55
|
-
|
|
56
|
-
response = smtp.sendmail(message,
|
|
57
|
-
|
|
52
|
+
envelope = Mail::SmtpEnvelope.new(mail)
|
|
53
|
+
response = smtp.sendmail(envelope.message, envelope.from, envelope.to)
|
|
58
54
|
settings[:return_response] ? response : self
|
|
59
55
|
end
|
|
60
|
-
|
|
61
56
|
end
|
|
62
57
|
end
|
|
@@ -1,45 +1,44 @@
|
|
|
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
|
|
11
|
-
include Mail::CheckDeliveryParams
|
|
12
|
-
|
|
13
11
|
# Provides a store of all the emails sent with the TestMailer so you can check them.
|
|
14
|
-
def
|
|
12
|
+
def self.deliveries
|
|
15
13
|
@@deliveries ||= []
|
|
16
14
|
end
|
|
17
15
|
|
|
18
16
|
# Allows you to over write the default deliveries store from an array to some
|
|
19
|
-
# other object. If you just want to clear the store,
|
|
17
|
+
# other object. If you just want to clear the store,
|
|
20
18
|
# call TestMailer.deliveries.clear.
|
|
21
|
-
#
|
|
19
|
+
#
|
|
22
20
|
# If you place another object here, please make sure it responds to:
|
|
23
|
-
#
|
|
21
|
+
#
|
|
24
22
|
# * << (message)
|
|
25
23
|
# * clear
|
|
26
24
|
# * length
|
|
27
25
|
# * size
|
|
28
26
|
# * and other common Array methods
|
|
29
|
-
def
|
|
27
|
+
def self.deliveries=(val)
|
|
30
28
|
@@deliveries = val
|
|
31
29
|
end
|
|
32
30
|
|
|
31
|
+
attr_accessor :settings
|
|
32
|
+
|
|
33
33
|
def initialize(values)
|
|
34
34
|
@settings = values.dup
|
|
35
35
|
end
|
|
36
|
-
|
|
37
|
-
attr_accessor :settings
|
|
38
36
|
|
|
39
37
|
def deliver!(mail)
|
|
40
|
-
|
|
38
|
+
# Create the envelope to validate it
|
|
39
|
+
Mail::SmtpEnvelope.new(mail)
|
|
40
|
+
|
|
41
41
|
Mail::TestMailer.deliveries << mail
|
|
42
42
|
end
|
|
43
|
-
|
|
44
43
|
end
|
|
45
44
|
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
|
|
|
@@ -29,7 +29,7 @@ module Mail
|
|
|
29
29
|
# order: order of emails returned. Possible values are :asc or :desc. Default value is :asc.
|
|
30
30
|
# count: number of emails to retrieve. The default value is 10. A value of 1 returns an
|
|
31
31
|
# instance of Message, not an array of Message instances.
|
|
32
|
-
# keys: are passed as criteria to the SEARCH command. They can either be a string holding the entire search string,
|
|
32
|
+
# keys: are passed as criteria to the SEARCH command. They can either be a string holding the entire search string,
|
|
33
33
|
# or a single-dimension array of search keywords and arguments. Refer to [IMAP] section 6.4.4 for a full list
|
|
34
34
|
# The default is 'ALL'
|
|
35
35
|
#
|
|
@@ -38,14 +38,15 @@ module Mail
|
|
|
38
38
|
#
|
|
39
39
|
class IMAP < Retriever
|
|
40
40
|
require 'net/imap' unless defined?(Net::IMAP)
|
|
41
|
-
|
|
41
|
+
|
|
42
42
|
def initialize(values)
|
|
43
43
|
self.settings = { :address => "localhost",
|
|
44
44
|
:port => 143,
|
|
45
45
|
:user_name => nil,
|
|
46
46
|
:password => nil,
|
|
47
47
|
:authentication => nil,
|
|
48
|
-
:enable_ssl => false
|
|
48
|
+
:enable_ssl => false,
|
|
49
|
+
:enable_starttls => false }.merge!(values)
|
|
49
50
|
end
|
|
50
51
|
|
|
51
52
|
attr_accessor :settings
|
|
@@ -64,17 +65,20 @@ module Mail
|
|
|
64
65
|
# This is helpful when you don't want your messages to be set to read automatically. Default is false.
|
|
65
66
|
# delete_after_find: flag for whether to delete each retreived email after find. Default
|
|
66
67
|
# is false. Use #find_and_delete if you would like this to default to true.
|
|
67
|
-
# keys: are passed as criteria to the SEARCH command. They can either be a string holding the entire search string,
|
|
68
|
+
# keys: are passed as criteria to the SEARCH command. They can either be a string holding the entire search string,
|
|
68
69
|
# or a single-dimension array of search keywords and arguments. Refer to [IMAP] section 6.4.4 for a full list
|
|
69
70
|
# The default is 'ALL'
|
|
71
|
+
# search_charset: charset to pass to IMAP server search. Omitted by default. Example: 'UTF-8' or 'ASCII'.
|
|
70
72
|
#
|
|
71
|
-
def find(options=
|
|
73
|
+
def find(options=nil, &block)
|
|
72
74
|
options = validate_options(options)
|
|
73
75
|
|
|
74
76
|
start do |imap|
|
|
75
77
|
options[:read_only] ? imap.examine(options[:mailbox]) : imap.select(options[:mailbox])
|
|
76
78
|
|
|
77
|
-
uids = imap.uid_search(options[:keys])
|
|
79
|
+
uids = imap.uid_search(options[:keys], options[:search_charset])
|
|
80
|
+
.to_a # older net-imap may return nil, newer may return ESearchResult struct
|
|
81
|
+
.sort # RFC3501 does _not_ require UIDs to be returned in order
|
|
78
82
|
uids.reverse! if options[:what].to_sym == :last
|
|
79
83
|
uids = uids.first(options[:count]) if options[:count].is_a?(Integer)
|
|
80
84
|
uids.reverse! if (options[:what].to_sym == :last && options[:order].to_sym == :asc) ||
|
|
@@ -83,14 +87,18 @@ module Mail
|
|
|
83
87
|
if block_given?
|
|
84
88
|
uids.each do |uid|
|
|
85
89
|
uid = options[:uid].to_i unless options[:uid].nil?
|
|
86
|
-
fetchdata = imap.uid_fetch(uid, ['RFC822'])[0]
|
|
90
|
+
fetchdata = imap.uid_fetch(uid, ['RFC822', 'FLAGS'])[0]
|
|
87
91
|
new_message = Mail.new(fetchdata.attr['RFC822'])
|
|
88
92
|
new_message.mark_for_delete = true if options[:delete_after_find]
|
|
89
|
-
|
|
93
|
+
|
|
94
|
+
if block.arity == 4
|
|
95
|
+
yield new_message, imap, uid, fetchdata.attr['FLAGS']
|
|
96
|
+
elsif block.arity == 3
|
|
90
97
|
yield new_message, imap, uid
|
|
91
98
|
else
|
|
92
99
|
yield new_message
|
|
93
100
|
end
|
|
101
|
+
|
|
94
102
|
imap.uid_store(uid, "+FLAGS", [Net::IMAP::DELETED]) if options[:delete_after_find] && new_message.is_marked_for_delete?
|
|
95
103
|
break unless options[:uid].nil?
|
|
96
104
|
end
|
|
@@ -116,6 +124,7 @@ module Mail
|
|
|
116
124
|
mailbox = Net::IMAP.encode_utf7(mailbox)
|
|
117
125
|
|
|
118
126
|
start do |imap|
|
|
127
|
+
imap.select(mailbox)
|
|
119
128
|
imap.uid_search(['ALL']).each do |uid|
|
|
120
129
|
imap.uid_store(uid, "+FLAGS", [Net::IMAP::DELETED])
|
|
121
130
|
end
|
|
@@ -136,7 +145,7 @@ module Mail
|
|
|
136
145
|
|
|
137
146
|
# Set default options
|
|
138
147
|
def validate_options(options)
|
|
139
|
-
options
|
|
148
|
+
options = options ? Hash[options] : {}
|
|
140
149
|
options[:mailbox] ||= 'INBOX'
|
|
141
150
|
options[:count] ||= 10
|
|
142
151
|
options[:order] ||= :asc
|
|
@@ -154,7 +163,14 @@ module Mail
|
|
|
154
163
|
def start(config=Mail::Configuration.instance, &block)
|
|
155
164
|
raise ArgumentError.new("Mail::Retrievable#imap_start takes a block") unless block_given?
|
|
156
165
|
|
|
166
|
+
if settings[:enable_starttls] && settings[:enable_ssl]
|
|
167
|
+
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."
|
|
168
|
+
end
|
|
169
|
+
|
|
157
170
|
imap = Net::IMAP.new(settings[:address], settings[:port], settings[:enable_ssl], nil, false)
|
|
171
|
+
|
|
172
|
+
imap.starttls if settings[:enable_starttls]
|
|
173
|
+
|
|
158
174
|
if settings[:authentication].nil?
|
|
159
175
|
imap.login(settings[:user_name], settings[:password])
|
|
160
176
|
else
|