mail 2.2.5 → 2.2.19

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.
Files changed (152) hide show
  1. data/CHANGELOG.rdoc +163 -7
  2. data/README.rdoc +56 -65
  3. data/Rakefile +31 -6
  4. data/lib/VERSION +2 -2
  5. data/lib/mail/attachments_list.rb +4 -4
  6. data/lib/mail/body.rb +6 -2
  7. data/lib/mail/configuration.rb +7 -1
  8. data/lib/mail/core_extensions/shellwords.rb +55 -0
  9. data/lib/mail/core_extensions/smtp.rb +24 -0
  10. data/lib/mail/elements/address.rb +6 -6
  11. data/lib/mail/elements/content_disposition_element.rb +1 -1
  12. data/lib/mail/elements/content_type_element.rb +2 -2
  13. data/lib/mail/encodings.rb +55 -57
  14. data/lib/mail/field.rb +2 -1
  15. data/lib/mail/field_list.rb +1 -1
  16. data/lib/mail/fields/common/common_field.rb +10 -9
  17. data/lib/mail/fields/common/common_message_id.rb +6 -5
  18. data/lib/mail/fields/common/parameter_hash.rb +14 -4
  19. data/lib/mail/fields/content_disposition_field.rb +1 -1
  20. data/lib/mail/fields/content_type_field.rb +41 -28
  21. data/lib/mail/fields/date_field.rb +3 -1
  22. data/lib/mail/fields/received_field.rb +11 -3
  23. data/lib/mail/fields/resent_date_field.rb +1 -1
  24. data/lib/mail/fields/return_path_field.rb +1 -0
  25. data/lib/mail/fields/unstructured_field.rb +4 -1
  26. data/lib/mail/header.rb +8 -5
  27. data/lib/mail/mail.rb +71 -57
  28. data/lib/mail/message.rb +518 -391
  29. data/lib/mail/network/delivery_methods/sendmail.rb +15 -15
  30. data/lib/mail/network/delivery_methods/smtp.rb +33 -6
  31. data/lib/mail/network/delivery_methods/smtp_connection.rb +74 -0
  32. data/lib/mail/network/retriever_methods/base.rb +63 -0
  33. data/lib/mail/network/retriever_methods/imap.rb +147 -7
  34. data/lib/mail/network/retriever_methods/pop3.rb +25 -44
  35. data/lib/mail/network/retriever_methods/test_retriever.rb +40 -0
  36. data/lib/mail/network.rb +4 -0
  37. data/lib/mail/parsers/address_lists.rb +2 -2
  38. data/lib/mail/parsers/address_lists.treetop +2 -2
  39. data/lib/mail/parsers/content_disposition.rb +166 -18
  40. data/lib/mail/parsers/content_disposition.treetop +1 -1
  41. data/lib/mail/parsers/content_type.rb +477 -49
  42. data/lib/mail/parsers/content_type.treetop +12 -2
  43. data/lib/mail/parsers/rfc2822.rb +58 -35
  44. data/lib/mail/parsers/rfc2822.treetop +2 -2
  45. data/lib/mail/part.rb +2 -2
  46. data/lib/mail/parts_list.rb +16 -8
  47. data/lib/mail/patterns.rb +7 -2
  48. data/lib/mail/utilities.rb +31 -1
  49. data/lib/mail/version.rb +10 -8
  50. data/lib/mail/version_specific/ruby_1_8.rb +2 -2
  51. data/lib/mail/version_specific/ruby_1_9.rb +29 -8
  52. data/lib/mail.rb +8 -4
  53. metadata +44 -110
  54. data/lib/mail/attachments_list.rbc +0 -1983
  55. data/lib/mail/body.rbc +0 -3809
  56. data/lib/mail/configuration.rbc +0 -1112
  57. data/lib/mail/core_extensions/nil.rbc +0 -244
  58. data/lib/mail/core_extensions/string.rbc +0 -0
  59. data/lib/mail/elements/address.rbc +0 -4112
  60. data/lib/mail/elements/address_list.rbc +0 -1309
  61. data/lib/mail/elements/content_disposition_element.rbc +0 -701
  62. data/lib/mail/elements/content_location_element.rbc +0 -573
  63. data/lib/mail/elements/content_transfer_encoding_element.rbc +0 -535
  64. data/lib/mail/elements/content_type_element.rbc +0 -786
  65. data/lib/mail/elements/date_time_element.rbc +0 -583
  66. data/lib/mail/elements/envelope_from_element.rbc +0 -771
  67. data/lib/mail/elements/message_ids_element.rbc +0 -740
  68. data/lib/mail/elements/mime_version_element.rbc +0 -583
  69. data/lib/mail/elements/phrase_list.rbc +0 -562
  70. data/lib/mail/elements/received_element.rbc +0 -725
  71. data/lib/mail/elements.rbc +0 -362
  72. data/lib/mail/encodings/7bit.rbc +0 -538
  73. data/lib/mail/encodings/8bit.rbc +0 -541
  74. data/lib/mail/encodings/base64.rbc +0 -629
  75. data/lib/mail/encodings/binary.rbc +0 -529
  76. data/lib/mail/encodings/quoted_printable.rbc +0 -766
  77. data/lib/mail/encodings/transfer_encoding.rbc +0 -1134
  78. data/lib/mail/encodings.rbc +0 -0
  79. data/lib/mail/envelope.rbc +0 -719
  80. data/lib/mail/field.rbc +0 -4708
  81. data/lib/mail/field_list.rbc +0 -518
  82. data/lib/mail/fields/bcc_field.rbc +0 -564
  83. data/lib/mail/fields/cc_field.rbc +0 -579
  84. data/lib/mail/fields/comments_field.rbc +0 -383
  85. data/lib/mail/fields/common/address_container.rbc +0 -363
  86. data/lib/mail/fields/common/common_address.rbc +0 -3550
  87. data/lib/mail/fields/common/common_date.rbc +0 -908
  88. data/lib/mail/fields/common/common_field.rbc +0 -973
  89. data/lib/mail/fields/common/common_message_id.rbc +0 -1051
  90. data/lib/mail/fields/common/parameter_hash.rbc +0 -1335
  91. data/lib/mail/fields/content_description_field.rbc +0 -396
  92. data/lib/mail/fields/content_disposition_field.rbc +0 -1440
  93. data/lib/mail/fields/content_id_field.rbc +0 -1236
  94. data/lib/mail/fields/content_location_field.rbc +0 -892
  95. data/lib/mail/fields/content_transfer_encoding_field.rbc +0 -1184
  96. data/lib/mail/fields/content_type_field.rbc +0 -3958
  97. data/lib/mail/fields/date_field.rbc +0 -712
  98. data/lib/mail/fields/from_field.rbc +0 -579
  99. data/lib/mail/fields/in_reply_to_field.rbc +0 -579
  100. data/lib/mail/fields/keywords_field.rbc +0 -979
  101. data/lib/mail/fields/message_id_field.rbc +0 -1008
  102. data/lib/mail/fields/mime_version_field.rbc +0 -1107
  103. data/lib/mail/fields/optional_field.rbc +0 -153
  104. data/lib/mail/fields/received_field.rbc +0 -1137
  105. data/lib/mail/fields/references_field.rbc +0 -574
  106. data/lib/mail/fields/reply_to_field.rbc +0 -579
  107. data/lib/mail/fields/resent_bcc_field.rbc +0 -579
  108. data/lib/mail/fields/resent_cc_field.rbc +0 -579
  109. data/lib/mail/fields/resent_date_field.rbc +0 -656
  110. data/lib/mail/fields/resent_from_field.rbc +0 -579
  111. data/lib/mail/fields/resent_message_id_field.rbc +0 -639
  112. data/lib/mail/fields/resent_sender_field.rbc +0 -731
  113. data/lib/mail/fields/resent_to_field.rbc +0 -579
  114. data/lib/mail/fields/return_path_field.rbc +0 -737
  115. data/lib/mail/fields/sender_field.rbc +0 -799
  116. data/lib/mail/fields/structured_field.rbc +0 -671
  117. data/lib/mail/fields/subject_field.rbc +0 -378
  118. data/lib/mail/fields/to_field.rbc +0 -579
  119. data/lib/mail/fields/unstructured_field.rbc +0 -2292
  120. data/lib/mail/fields.rbc +0 -782
  121. data/lib/mail/header.rbc +0 -3720
  122. data/lib/mail/mail.rbc +0 -2168
  123. data/lib/mail/message.rbc +0 -19034
  124. data/lib/mail/network/delivery_methods/file_delivery.rbc +0 -722
  125. data/lib/mail/network/delivery_methods/sendmail.rbc +0 -800
  126. data/lib/mail/network/delivery_methods/smtp.rbc +0 -1081
  127. data/lib/mail/network/delivery_methods/test_mailer.rbc +0 -552
  128. data/lib/mail/network/retriever_methods/pop3.rbc +0 -2447
  129. data/lib/mail/network.rbc +0 -236
  130. data/lib/mail/parsers/address_lists.rbc +0 -1307
  131. data/lib/mail/parsers/content_disposition.rbc +0 -5968
  132. data/lib/mail/parsers/content_location.rbc +0 -2166
  133. data/lib/mail/parsers/content_transfer_encoding.rbc +0 -2591
  134. data/lib/mail/parsers/content_type.rbc +0 -7949
  135. data/lib/mail/parsers/date_time.rbc +0 -1836
  136. data/lib/mail/parsers/envelope_from.rbc +0 -3106
  137. data/lib/mail/parsers/message_ids.rbc +0 -989
  138. data/lib/mail/parsers/mime_version.rbc +0 -2254
  139. data/lib/mail/parsers/phrase_lists.rbc +0 -989
  140. data/lib/mail/parsers/received.rbc +0 -1267
  141. data/lib/mail/parsers/rfc2045.rbc +0 -5614
  142. data/lib/mail/parsers/rfc2822.rbc +0 -74848
  143. data/lib/mail/parsers/rfc2822_obsolete.rbc +0 -55220
  144. data/lib/mail/part.rbc +0 -2314
  145. data/lib/mail/parts_list.rbc +0 -832
  146. data/lib/mail/patterns.rbc +0 -0
  147. data/lib/mail/utilities.rbc +0 -2377
  148. data/lib/mail/version.rbc +0 -450
  149. data/lib/mail/version_specific/ruby_1_8.rbc +0 -2496
  150. data/lib/mail.rbc +0 -1151
  151. data/lib/tasks/corpus.rake.compiled.rbc +0 -2195
  152. data/lib/tasks/treetop.rake.compiled.rbc +0 -297
@@ -1,57 +1,57 @@
1
1
  module Mail
2
2
  # A delivery method implementation which sends via sendmail.
3
- #
3
+ #
4
4
  # To use this, first find out where the sendmail binary is on your computer,
5
5
  # if you are on a mac or unix box, it is usually in /usr/sbin/sendmail, this will
6
6
  # be your sendmail location.
7
- #
7
+ #
8
8
  # Mail.defaults do
9
9
  # delivery_method :sendmail
10
10
  # end
11
- #
11
+ #
12
12
  # Or if your sendmail binary is not at '/usr/sbin/sendmail'
13
- #
13
+ #
14
14
  # Mail.defaults do
15
15
  # delivery_method :sendmail, :location => '/absolute/path/to/your/sendmail'
16
16
  # end
17
- #
17
+ #
18
18
  # Then just deliver the email as normal:
19
- #
19
+ #
20
20
  # Mail.deliver do
21
21
  # to 'mikel@test.lindsaar.net'
22
22
  # from 'ada@test.lindsaar.net'
23
23
  # subject 'testing sendmail'
24
24
  # body 'testing sendmail'
25
25
  # end
26
- #
26
+ #
27
27
  # Or by calling deliver on a Mail message
28
- #
28
+ #
29
29
  # mail = Mail.new do
30
30
  # to 'mikel@test.lindsaar.net'
31
31
  # from 'ada@test.lindsaar.net'
32
32
  # subject 'testing sendmail'
33
33
  # body 'testing sendmail'
34
34
  # end
35
- #
35
+ #
36
36
  # mail.deliver!
37
37
  class Sendmail
38
-
38
+
39
39
  def initialize(values)
40
40
  self.settings = { :location => '/usr/sbin/sendmail',
41
41
  :arguments => '-i -t' }.merge(values)
42
42
  end
43
-
43
+
44
44
  attr_accessor :settings
45
45
 
46
46
  def deliver!(mail)
47
47
  envelope_from = mail.return_path || mail.sender || mail.from_addrs.first
48
- return_path = "-f \"#{envelope_from}\"" if envelope_from
48
+ return_path = "-f \"#{envelope_from.to_s.shellescape}\"" if envelope_from
49
49
 
50
50
  arguments = [settings[:arguments], return_path].compact.join(" ")
51
-
52
- Sendmail.call(settings[:location], arguments, mail.destinations.join(" "), mail)
51
+
52
+ Sendmail.call(settings[:location], arguments, mail.destinations.collect(&:shellescape).join(" "), mail)
53
53
  end
54
-
54
+
55
55
  def Sendmail.call(path, arguments, destinations, mail)
56
56
  IO.popen("#{path} #{arguments} #{destinations}", "w+") do |io|
57
57
  io.puts mail.encoded.to_lf
@@ -34,6 +34,18 @@ module Mail
34
34
  # :enable_starttls_auto => true }
35
35
  # end
36
36
  #
37
+ # === Certificate verification
38
+ #
39
+ # When using TLS, some mail servers provide certificates that are self-signed
40
+ # or whose names do not exactly match the hostname given in the address.
41
+ # OpenSSL will reject these by default. The best remedy is to use the correct
42
+ # hostname or update the certificate authorities trusted by your ruby. If
43
+ # that isn't possible, you can control this behavior with
44
+ # an :openssl_verify_mode setting. Its value may be either an OpenSSL
45
+ # verify mode constant (OpenSSL::SSL::VERIFY_NONE), or a string containing
46
+ # the name of an OpenSSL verify mode (none, peer, client_once,
47
+ # fail_if_no_peer_cert).
48
+ #
37
49
  # === Others
38
50
  #
39
51
  # Feel free to send me other examples that were tricky
@@ -68,7 +80,9 @@ module Mail
68
80
  :user_name => nil,
69
81
  :password => nil,
70
82
  :authentication => nil,
71
- :enable_starttls_auto => true }.merge!(values)
83
+ :enable_starttls_auto => true,
84
+ :openssl_verify_mode => nil
85
+ }.merge!(values)
72
86
  end
73
87
 
74
88
  attr_accessor :settings
@@ -95,16 +109,29 @@ module Mail
95
109
 
96
110
  smtp = Net::SMTP.new(settings[:address], settings[:port])
97
111
  if settings[:enable_starttls_auto]
98
- smtp.enable_starttls_auto if smtp.respond_to?(:enable_starttls_auto)
112
+ if smtp.respond_to?(:enable_starttls_auto)
113
+ unless settings[:openssl_verify_mode]
114
+ smtp.enable_starttls_auto
115
+ else
116
+ openssl_verify_mode = settings[:openssl_verify_mode]
117
+ if openssl_verify_mode.kind_of?(String)
118
+ openssl_verify_mode = "OpenSSL::SSL::VERIFY_#{openssl_verify_mode.upcase}".constantize
119
+ end
120
+ context = Net::SMTP.default_ssl_context
121
+ context.verify_mode = openssl_verify_mode
122
+ smtp.enable_starttls_auto(context)
123
+ end
124
+ end
99
125
  end
100
126
 
127
+ response = nil
101
128
  smtp.start(settings[:domain], settings[:user_name], settings[:password], settings[:authentication]) do |smtp|
102
- smtp.sendmail(message, envelope_from, destinations)
129
+ response = smtp.sendmail(message, envelope_from, destinations)
103
130
  end
104
-
105
- self
131
+
132
+ return settings[:return_response] ? response : self
106
133
  end
107
134
 
108
135
 
109
136
  end
110
- end
137
+ end
@@ -0,0 +1,74 @@
1
+ module Mail
2
+ # == Sending Email with SMTP
3
+ #
4
+ # Mail allows you to send emails using an open SMTP connection. This is done by
5
+ # passing a created Net::SMTP object. This way we can get better performance to
6
+ # our local mail server by reducing the number of connections at any one time.
7
+ #
8
+ # === Sending via SMTP server on Localhost
9
+ #
10
+ # To send mail open a connection with Net::Smtp using any options you like
11
+ # === Delivering the email
12
+ #
13
+ # Once you have the settings right, sending the email is done by:
14
+ #
15
+ # smtp_conn = Net::SMTP.start(settings[:address], settings[:port])
16
+ # Mail.defaults do
17
+ # delivery_method :smtp_connection, { :connection => smtp_conn }
18
+ # end
19
+ #
20
+ # Mail.deliver do
21
+ # to 'mikel@test.lindsaar.net'
22
+ # from 'ada@test.lindsaar.net'
23
+ # subject 'testing sendmail'
24
+ # body 'testing sendmail'
25
+ # end
26
+ #
27
+ # Or by calling deliver on a Mail message
28
+ #
29
+ # mail = Mail.new do
30
+ # to 'mikel@test.lindsaar.net'
31
+ # from 'ada@test.lindsaar.net'
32
+ # subject 'testing sendmail'
33
+ # body 'testing sendmail'
34
+ # end
35
+ #
36
+ # mail.deliver!
37
+ class SMTPConnection
38
+
39
+ def initialize(values)
40
+ raise ArgumentError.new('A Net::SMTP object is required for this delivery method') if values[:connection].nil?
41
+ self.smtp = values[:connection]
42
+ self.settings = values
43
+ end
44
+
45
+ attr_accessor :smtp
46
+ attr_accessor :settings
47
+
48
+ # Send the message via SMTP.
49
+ # The from and to attributes are optional. If not set, they are retrieve from the Message.
50
+ def deliver!(mail)
51
+
52
+ # Set the envelope from to be either the return-path, the sender or the first from address
53
+ envelope_from = mail.return_path || mail.sender || mail.from_addrs.first
54
+ if envelope_from.blank?
55
+ raise ArgumentError.new('A sender (Return-Path, Sender or From) required to send a message')
56
+ end
57
+
58
+ destinations ||= mail.destinations if mail.respond_to?(:destinations) && mail.destinations
59
+ if destinations.blank?
60
+ raise ArgumentError.new('At least one recipient (To, Cc or Bcc) is required to send a message')
61
+ end
62
+
63
+ message ||= mail.encoded if mail.respond_to?(:encoded)
64
+ if message.blank?
65
+ raise ArgumentError.new('A encoded content is required to send a message')
66
+ end
67
+
68
+ response = smtp.sendmail(message, envelope_from, destinations)
69
+
70
+ settings[:return_response] ? response : self
71
+ end
72
+
73
+ end
74
+ end
@@ -0,0 +1,63 @@
1
+ # encoding: utf-8
2
+
3
+ module Mail
4
+
5
+ class Retriever
6
+
7
+ # Get the oldest received email(s)
8
+ #
9
+ # Possible options:
10
+ # count: number of emails to retrieve. The default value is 1.
11
+ # order: order of emails returned. Possible values are :asc or :desc. Default value is :asc.
12
+ #
13
+ def first(options = {}, &block)
14
+ options ||= {}
15
+ options[:what] = :first
16
+ options[:count] ||= 1
17
+ find(options, &block)
18
+ end
19
+
20
+ # Get the most recent received email(s)
21
+ #
22
+ # Possible options:
23
+ # count: number of emails to retrieve. The default value is 1.
24
+ # order: order of emails returned. Possible values are :asc or :desc. Default value is :asc.
25
+ #
26
+ def last(options = {}, &block)
27
+ options ||= {}
28
+ options[:what] = :last
29
+ options[:count] ||= 1
30
+ find(options, &block)
31
+ end
32
+
33
+ # Get all emails.
34
+ #
35
+ # Possible options:
36
+ # order: order of emails returned. Possible values are :asc or :desc. Default value is :asc.
37
+ #
38
+ def all(options = {}, &block)
39
+ options ||= {}
40
+ options[:count] = :all
41
+ find(options, &block)
42
+ end
43
+
44
+ # Find emails in the mailbox, and then deletes them. Without any options, the
45
+ # five last received emails are returned.
46
+ #
47
+ # Possible options:
48
+ # what: last or first emails. The default is :first.
49
+ # order: order of emails returned. Possible values are :asc or :desc. Default value is :asc.
50
+ # count: number of emails to retrieve. The default value is 10. A value of 1 returns an
51
+ # instance of Message, not an array of Message instances.
52
+ # delete_after_find: flag for whether to delete each retreived email after find. Default
53
+ # is true. Call #find if you would like this to default to false.
54
+ #
55
+ def find_and_delete(options = {}, &block)
56
+ options ||= {}
57
+ options[:delete_after_find] ||= true
58
+ find(options, &block)
59
+ end
60
+
61
+ end
62
+
63
+ end
@@ -1,18 +1,158 @@
1
+ # encoding: utf-8
2
+
1
3
  module Mail
2
- class IMAP
4
+ # The IMAP retriever allows to get the last, first or all emails from a IMAP server.
5
+ # Each email retrieved (RFC2822) is given as an instance of +Message+.
6
+ #
7
+ # While being retrieved, emails can be yielded if a block is given.
8
+ #
9
+ # === Example of retrieving Emails from GMail:
10
+ #
11
+ # Mail.defaults do
12
+ # retriever_method :imap, { :address => "imap.googlemail.com",
13
+ # :port => 993,
14
+ # :user_name => '<username>',
15
+ # :password => '<password>',
16
+ # :enable_ssl => true }
17
+ # end
18
+ #
19
+ # Mail.all #=> Returns an array of all emails
20
+ # Mail.first #=> Returns the first unread email
21
+ # Mail.last #=> Returns the first unread email
22
+ #
23
+ # You can also pass options into Mail.find to locate an email in your imap mailbox
24
+ # with the following options:
25
+ #
26
+ # mailbox: name of the mailbox used for email retrieval. The default is 'INBOX'.
27
+ # what: last or first emails. The default is :first.
28
+ # order: order of emails returned. Possible values are :asc or :desc. Default value is :asc.
29
+ # count: number of emails to retrieve. The default value is 10. A value of 1 returns an
30
+ # instance of Message, not an array of Message instances.
31
+ #
32
+ # Mail.find(:what => :first, :count => 10, :order => :asc)
33
+ # #=> Returns the first 10 emails in ascending order
34
+ #
35
+ class IMAP < Retriever
36
+ require 'net/imap'
3
37
 
4
38
  def initialize(values)
5
39
  self.settings = { :address => "localhost",
6
- :port => 110,
40
+ :port => 143,
7
41
  :user_name => nil,
8
42
  :password => nil,
9
43
  :authentication => nil,
10
44
  :enable_ssl => false }.merge!(values)
11
45
  end
12
-
13
- def IMAP.get_messages(&block)
14
- # To be implemented
46
+
47
+ attr_accessor :settings
48
+
49
+ # Find emails in a IMAP mailbox. Without any options, the 10 last received emails are returned.
50
+ #
51
+ # Possible options:
52
+ # mailbox: mailbox to search the email(s) in. The default is 'INBOX'.
53
+ # what: last or first emails. The default is :first.
54
+ # order: order of emails returned. Possible values are :asc or :desc. Default value is :asc.
55
+ # count: number of emails to retrieve. The default value is 10. A value of 1 returns an
56
+ # instance of Message, not an array of Message instances.
57
+ # delete_after_find: flag for whether to delete each retreived email after find. Default
58
+ # is false. Use #find_and_delete if you would like this to default to true.
59
+ #
60
+ def find(options={}, &block)
61
+ options = validate_options(options)
62
+
63
+ start do |imap|
64
+ imap.select(options[:mailbox])
65
+
66
+ message_ids = imap.uid_search(options[:keys])
67
+ message_ids.reverse! if options[:what].to_sym == :last
68
+ message_ids = message_ids.first(options[:count]) if options[:count].is_a?(Integer)
69
+ message_ids.reverse! if (options[:what].to_sym == :last && options[:order].to_sym == :asc) ||
70
+ (options[:what].to_sym != :last && options[:order].to_sym == :desc)
71
+
72
+ if block_given?
73
+ message_ids.each do |message_id|
74
+ fetchdata = imap.uid_fetch(message_id, ['RFC822'])[0]
75
+ new_message = Mail.new(fetchdata.attr['RFC822'])
76
+ new_message.mark_for_delete = true if options[:delete_after_find]
77
+ if block.arity == 3
78
+ yield new_message, imap, message_id
79
+ else
80
+ yield new_message
81
+ end
82
+ imap.uid_store(message_id, "+FLAGS", [Net::IMAP::DELETED]) if options[:delete_after_find] && new_message.is_marked_for_delete?
83
+ end
84
+ imap.expunge if options[:delete_after_find]
85
+ else
86
+ emails = []
87
+ message_ids.each do |message_id|
88
+ fetchdata = imap.uid_fetch(message_id, ['RFC822'])[0]
89
+ emails << Mail.new(fetchdata.attr['RFC822'])
90
+ imap.uid_store(message_id, "+FLAGS", [Net::IMAP::DELETED]) if options[:delete_after_find]
91
+ end
92
+ imap.expunge if options[:delete_after_find]
93
+ emails.size == 1 && options[:count] == 1 ? emails.first : emails
94
+ end
95
+ end
15
96
  end
16
-
97
+
98
+ # Delete all emails from a IMAP mailbox
99
+ def delete_all(mailbox='INBOX')
100
+ mailbox ||= 'INBOX'
101
+ mailbox = Net::IMAP.encode_utf7(mailbox)
102
+
103
+ start do |imap|
104
+ imap.select(mailbox)
105
+ imap.uid_search(['ALL']).each do |message_id|
106
+ imap.uid_store(message_id, "+FLAGS", [Net::IMAP::DELETED])
107
+ end
108
+ imap.expunge
109
+ end
110
+ end
111
+
112
+ # Returns the connection object of the retrievable (IMAP or POP3)
113
+ def connection(&block)
114
+ raise ArgumentError.new('Mail::Retrievable#connection takes a block') unless block_given?
115
+
116
+ start do |imap|
117
+ yield imap
118
+ end
119
+ end
120
+
121
+ private
122
+
123
+ # Set default options
124
+ def validate_options(options)
125
+ options ||= {}
126
+ options[:mailbox] ||= 'INBOX'
127
+ options[:count] ||= 10
128
+ options[:order] ||= :asc
129
+ options[:what] ||= :first
130
+ options[:keys] ||= 'ALL'
131
+ options[:delete_after_find] ||= false
132
+ options[:mailbox] = Net::IMAP.encode_utf7(options[:mailbox])
133
+
134
+ options
135
+ end
136
+
137
+ # Start an IMAP session and ensures that it will be closed in any case.
138
+ def start(config=Mail::Configuration.instance, &block)
139
+ raise ArgumentError.new("Mail::Retrievable#imap_start takes a block") unless block_given?
140
+
141
+ imap = Net::IMAP.new(settings[:address], settings[:port], settings[:enable_ssl], nil, false)
142
+ if settings[:authentication].nil?
143
+ imap.login(settings[:user_name], settings[:password])
144
+ else
145
+ # Note that Net::IMAP#authenticate('LOGIN', ...) is not equal with Net::IMAP#login(...)!
146
+ # (see also http://www.ensta.fr/~diam/ruby/online/ruby-doc-stdlib/libdoc/net/imap/rdoc/classes/Net/IMAP.html#M000718)
147
+ imap.authenticate(settings[:authentication], settings[:user_name], settings[:password])
148
+ end
149
+
150
+ yield imap
151
+ ensure
152
+ if defined?(imap) && imap && !imap.disconnected?
153
+ imap.disconnect
154
+ end
155
+ end
156
+
17
157
  end
18
- end
158
+ end
@@ -31,7 +31,7 @@ module Mail
31
31
  # Mail.find(:what => :first, :count => 10, :order => :asc)
32
32
  # #=> Returns the first 10 emails in ascending order
33
33
  #
34
- class POP3
34
+ class POP3 < Retriever
35
35
  require 'net/pop'
36
36
 
37
37
  def initialize(values)
@@ -45,43 +45,6 @@ module Mail
45
45
 
46
46
  attr_accessor :settings
47
47
 
48
- # Get the oldest received email(s)
49
- #
50
- # Possible options:
51
- # count: number of emails to retrieve. The default value is 1.
52
- # order: order of emails returned. Possible values are :asc or :desc. Default value is :asc.
53
- #
54
- def first(options = {}, &block)
55
- options ||= {}
56
- options[:what] = :first
57
- options[:count] ||= 1
58
- find(options, &block)
59
- end
60
-
61
- # Get the most recent received email(s)
62
- #
63
- # Possible options:
64
- # count: number of emails to retrieve. The default value is 1.
65
- # order: order of emails returned. Possible values are :asc or :desc. Default value is :asc.
66
- #
67
- def last(options = {}, &block)
68
- options ||= {}
69
- options[:what] = :last
70
- options[:count] ||= 1
71
- find(options, &block)
72
- end
73
-
74
- # Get all emails.
75
- #
76
- # Possible options:
77
- # order: order of emails returned. Possible values are :asc or :desc. Default value is :asc.
78
- #
79
- def all(options = {}, &block)
80
- options ||= {}
81
- options[:count] = :all
82
- find(options, &block)
83
- end
84
-
85
48
  # Find emails in a POP3 mailbox. Without any options, the 5 last received emails are returned.
86
49
  #
87
50
  # Possible options:
@@ -89,12 +52,15 @@ module Mail
89
52
  # order: order of emails returned. Possible values are :asc or :desc. Default value is :asc.
90
53
  # count: number of emails to retrieve. The default value is 10. A value of 1 returns an
91
54
  # instance of Message, not an array of Message instances.
55
+ # delete_after_find: flag for whether to delete each retreived email after find. Default
56
+ # is false. Use #find_and_delete if you would like this to default to true.
92
57
  #
93
58
  def find(options = {}, &block)
94
59
  options = validate_options(options)
95
60
 
96
61
  start do |pop3|
97
62
  mails = pop3.mails
63
+ pop3.reset # Clears all "deleted" marks. This prevents non-explicit/accidental deletions due to server settings.
98
64
  mails.sort! { |m1, m2| m2.number <=> m1.number } if options[:what] == :last
99
65
  mails = mails.first(options[:count]) if options[:count].is_a? Integer
100
66
 
@@ -105,12 +71,16 @@ module Mail
105
71
 
106
72
  if block_given?
107
73
  mails.each do |mail|
108
- yield Mail.new(mail.pop)
74
+ new_message = Mail.new(mail.pop)
75
+ new_message.mark_for_delete = true if options[:delete_after_find]
76
+ yield new_message
77
+ mail.delete if options[:delete_after_find] && new_message.is_marked_for_delete? # Delete if still marked for delete
109
78
  end
110
79
  else
111
80
  emails = []
112
81
  mails.each do |mail|
113
82
  emails << Mail.new(mail.pop)
83
+ mail.delete if options[:delete_after_find]
114
84
  end
115
85
  emails.size == 1 && options[:count] == 1 ? emails.first : emails
116
86
  end
@@ -127,6 +97,15 @@ module Mail
127
97
  end
128
98
  end
129
99
  end
100
+
101
+ # Returns the connection object of the retrievable (IMAP or POP3)
102
+ def connection(&block)
103
+ raise ArgumentError.new('Mail::Retrievable#connection takes a block') unless block_given?
104
+
105
+ start do |pop3|
106
+ yield pop3
107
+ end
108
+ end
130
109
 
131
110
  private
132
111
 
@@ -136,11 +115,14 @@ module Mail
136
115
  options[:count] ||= 10
137
116
  options[:order] ||= :asc
138
117
  options[:what] ||= :first
118
+ options[:delete_after_find] ||= false
139
119
  options
140
120
  end
141
121
 
142
- # Start a POP3 session and ensures that it will be closed in any case.
143
- def start(config = Mail::Configuration.instance, &block)
122
+ # Start a POP3 session and ensure that it will be closed in any case. Any messages
123
+ # marked for deletion via #find_and_delete or with the :delete_after_find option
124
+ # will be deleted when the session is closed.
125
+ def start(config = Configuration.instance, &block)
144
126
  raise ArgumentError.new("Mail::Retrievable#pop3_start takes a block") unless block_given?
145
127
 
146
128
  pop3 = Net::POP3.new(settings[:address], settings[:port], isapop = false)
@@ -150,10 +132,9 @@ module Mail
150
132
  yield pop3
151
133
  ensure
152
134
  if defined?(pop3) && pop3 && pop3.started?
153
- pop3.reset # This clears all "deleted" marks from messages.
154
135
  pop3.finish
155
136
  end
156
137
  end
157
-
138
+
158
139
  end
159
- end
140
+ end
@@ -0,0 +1,40 @@
1
+ # encoding: utf-8
2
+
3
+ module Mail
4
+
5
+ class TestRetriever < Retriever
6
+ cattr_accessor :emails
7
+
8
+ def initialize(values)
9
+ @@emails = []
10
+ end
11
+
12
+ def find(options = {}, &block)
13
+ options[:count] ||= :all
14
+ options[:order] ||= :asc
15
+ options[:what] ||= :first
16
+ emails = @@emails.dup
17
+ emails.reverse! if options[:what] == :last
18
+ emails = case count = options[:count]
19
+ when :all then emails
20
+ when 1 then emails.first
21
+ when Fixnum then emails[0, count]
22
+ else
23
+ raise 'Invalid count option value: ' + count.inspect
24
+ end
25
+ if options[:what] == :last && options[:order] == :asc || options[:what] == :first && options[:order] == :desc
26
+ emails.reverse!
27
+ end
28
+ emails.each { |email| email.mark_for_delete = true } if options[:delete_after_find]
29
+ if block_given?
30
+ emails.each { |email| yield email }
31
+ else
32
+ emails
33
+ end.tap do |results|
34
+ emails.each { |email| @@emails.delete(email) if email.is_marked_for_delete? } if options[:delete_after_find]
35
+ end
36
+ end
37
+
38
+ end
39
+
40
+ end
data/lib/mail/network.rb CHANGED
@@ -1,9 +1,13 @@
1
+ require 'mail/network/retriever_methods/base'
2
+
1
3
  module Mail
2
4
  autoload :SMTP, 'mail/network/delivery_methods/smtp'
3
5
  autoload :FileDelivery, 'mail/network/delivery_methods/file_delivery'
4
6
  autoload :Sendmail, 'mail/network/delivery_methods/sendmail'
7
+ autoload :SMTPConnection, 'mail/network/delivery_methods/smtp_connection'
5
8
  autoload :TestMailer, 'mail/network/delivery_methods/test_mailer'
6
9
 
7
10
  autoload :POP3, 'mail/network/retriever_methods/pop3'
8
11
  autoload :IMAP, 'mail/network/retriever_methods/imap'
12
+ autoload :TestRetriever, 'mail/network/retriever_methods/test_retriever'
9
13
  end
@@ -13,7 +13,7 @@ module Mail
13
13
 
14
14
  module PrimaryAddress0
15
15
  def addresses
16
- [first_addr] + other_addr.elements.map { |o| o.addr_value }
16
+ ([first_addr] + other_addr.elements.map { |o| o.addr_value }).reject { |e| e.empty? }
17
17
  end
18
18
  end
19
19
 
@@ -61,4 +61,4 @@ module Mail
61
61
  include AddressLists
62
62
  end
63
63
 
64
- end
64
+ end
@@ -6,7 +6,7 @@ module Mail
6
6
  rule primary_address
7
7
  address_list {
8
8
  def addresses
9
- [first_addr] + other_addr.elements.map { |o| o.addr_value }
9
+ ([first_addr] + other_addr.elements.map { |o| o.addr_value }).reject { |e| e.empty? }
10
10
  end
11
11
  } / obs_addr_list {
12
12
  def addresses
@@ -16,4 +16,4 @@ module Mail
16
16
  end
17
17
 
18
18
  end
19
- end
19
+ end