mail 2.2.6.1 → 2.2.7

Sign up to get free protection for your applications and to get access to all the features.

Potentially problematic release.


This version of mail might be problematic. Click here for more details.

@@ -1,3 +1,18 @@
1
+ == Thu Oct 7 15:44:31 UTC 2010 Mikel Lindsaar <mikel@rubyx.com>
2
+
3
+ * Version Bump to 2.2.7
4
+ * Release 2.2.7
5
+
6
+ == Thu Oct 7 15:42:57 UTC 2010 Mikel Lindsaar <mikel@rubyx.com>
7
+
8
+ * Added fix for Windows using 'rb' flags, thanks to Luis Lavena and dzhang for pointing it out
9
+ * Fixed up Rakefile to require bundler to run specs and give more appropriate errors messages if this fails
10
+
11
+ == Tue Sep 28 14:59:03 UTC 2010 Mikel Lindsaar <mikel@rubyx.com>
12
+
13
+ * Merged POP3 delete support work from Michael Prendergast
14
+ * Merged IMAP support work from Fabian Staubli
15
+
1
16
  == Mon Sep 13 02:31:21 UTC 2010 Mikel Lindsaar <mikel@rubyx.com>
2
17
 
3
18
  * Replace some missing documentation
data/Rakefile CHANGED
@@ -1,3 +1,24 @@
1
+ begin
2
+ require "rubygems"
3
+ require "bundler"
4
+ rescue LoadError
5
+ raise "Could not load the bundler gem. Install it with `gem install bundler`."
6
+ end
7
+
8
+ if Gem::Version.new(Bundler::VERSION) <= Gem::Version.new("1.0.0")
9
+ raise RuntimeError, "Your bundler version is too old for Mail" +
10
+ "Run `gem install bundler` to upgrade."
11
+ end
12
+
13
+ begin
14
+ # Set up load paths for all bundled gems
15
+ ENV["BUNDLE_GEMFILE"] = File.expand_path("../Gemfile", __FILE__)
16
+ Bundler.setup
17
+ rescue Bundler::GemNotFound
18
+ raise RuntimeError, "Bundler couldn't find some gems." +
19
+ "Did you run `bundle install`?"
20
+ end
21
+
1
22
  require File.expand_path('../spec/environment', __FILE__)
2
23
 
3
24
  require 'rake/rdoctask'
@@ -1,4 +1,4 @@
1
- patch:6
1
+ patch:7
2
2
  major:2
3
- build:1
3
+ build:
4
4
  minor:2
@@ -53,6 +53,8 @@ module Mail
53
53
  Mail::POP3
54
54
  when :pop3
55
55
  Mail::POP3
56
+ when :imap
57
+ Mail::IMAP
56
58
  else
57
59
  method
58
60
  end
@@ -64,4 +66,4 @@ module Mail
64
66
 
65
67
  end
66
68
 
67
- end
69
+ end
@@ -104,7 +104,7 @@ module Mail
104
104
  # a.local #=> 'mikel'
105
105
  def local
106
106
  parse unless @parsed
107
- "#{obs_domain_list}#{get_local.strip}"
107
+ "#{obs_domain_list}#{get_local.strip}" if get_local
108
108
  end
109
109
 
110
110
  # Returns the domain part (the right hand side of the @ sign in the email address) of
@@ -297,7 +297,7 @@ module Mail
297
297
  when tree.respond_to?(:addr_spec)
298
298
  tree.addr_spec.local_part.text_value
299
299
  else
300
- tree.local_part.text_value
300
+ tree ? tree.local_part.text_value : nil
301
301
  end
302
302
  end
303
303
 
@@ -147,6 +147,12 @@ module Mail
147
147
  retriever_method.find(*args, &block)
148
148
  end
149
149
 
150
+ # Finds and then deletes retrieved emails from a POP3 server.
151
+ # See Mail::POP3 for a complete documentation.
152
+ def self.find_and_delete(*args, &block)
153
+ retriever_method.find_and_delete(*args, &block)
154
+ end
155
+
150
156
  # Receive the first email(s) from a Pop3 server.
151
157
  # See Mail::POP3 for a complete documentation.
152
158
  def self.first(*args, &block)
@@ -167,7 +173,7 @@ module Mail
167
173
 
168
174
  # Reads in an email message from a path and instantiates it as a new Mail::Message
169
175
  def self.read(filename)
170
- self.new(File.read(filename))
176
+ self.new(File.open(filename, 'rb') { |f| f.read })
171
177
  end
172
178
 
173
179
  # Delete all emails from a POP3 server.
@@ -181,6 +187,10 @@ module Mail
181
187
  Mail.new(mail_as_string)
182
188
  end
183
189
 
190
+ def Mail.connection(&block)
191
+ retriever_method.connection(&block)
192
+ end
193
+
184
194
  # Initialize the observers and interceptors arrays
185
195
  @@delivery_notification_observers = []
186
196
  @@delivery_interceptors = []
@@ -115,6 +115,8 @@ module Mail
115
115
  @delivery_method = Mail.delivery_method.dup
116
116
 
117
117
  @transport_encoding = Mail::Encodings.get_encoding('7bit')
118
+
119
+ @mark_for_delete = false
118
120
 
119
121
  if args.flatten.first.respond_to?(:each_pair)
120
122
  init_with_hash(args.flatten.first)
@@ -1622,10 +1624,10 @@ module Mail
1622
1624
  add_multipart_mixed_header
1623
1625
  if values.is_a?(String)
1624
1626
  basename = File.basename(values)
1625
- filedata = File.read(values)
1627
+ filedata = File.open(values, 'rb') { |f| f.read }
1626
1628
  else
1627
1629
  basename = values[:filename]
1628
- filedata = values[:content] || File.read(values[:filename])
1630
+ filedata = values[:content] || File.open(values[:filename], 'rb') { |f| f.read }
1629
1631
  end
1630
1632
  self.attachments[basename] = filedata
1631
1633
  end
@@ -1720,7 +1722,36 @@ module Mail
1720
1722
  def find_first_mime_type(mt)
1721
1723
  all_parts.detect { |p| p.mime_type == mt }
1722
1724
  end
1723
-
1725
+
1726
+ # Skips the deletion of this message. All other messages
1727
+ # flagged for delete still will be deleted at session close (i.e. when
1728
+ # #find exits). Only has an effect if you're using #find_and_delete
1729
+ # or #find with :delete_after_find set to true.
1730
+ def skip_deletion
1731
+ @mark_for_delete = false
1732
+ end
1733
+
1734
+ # Sets whether this message should be deleted at session close (i.e.
1735
+ # after #find). Message will only be deleted if messages are retrieved
1736
+ # using the #find_and_delete method, or by calling #find with
1737
+ # :delete_after_find set to true.
1738
+ def mark_for_delete=(value = true)
1739
+ @mark_for_delete = value
1740
+ end
1741
+
1742
+ # Returns whether message will be marked for deletion.
1743
+ # If so, the message will be deleted at session close (i.e. after #find
1744
+ # exits), but only if also using the #find_and_delete method, or by
1745
+ # calling #find with :delete_after_find set to true.
1746
+ #
1747
+ # Side-note: Just to be clear, this method will return true even if
1748
+ # the message hasn't yet been marked for delete on the mail server.
1749
+ # However, if this method returns true, it *will be* marked on the
1750
+ # server after each block yields back to #find or #find_and_delete.
1751
+ def is_marked_for_delete?
1752
+ return @mark_for_delete
1753
+ end
1754
+
1724
1755
  private
1725
1756
 
1726
1757
  # 2.1. General Description
@@ -1,5 +1,39 @@
1
+ # encoding: utf-8
2
+
1
3
  module Mail
4
+ # The IMAP retriever allows to get the last, first or all emails from a POP3 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
+ #
2
35
  class IMAP
36
+ require 'net/imap'
3
37
 
4
38
  def initialize(values)
5
39
  self.settings = { :address => "localhost",
@@ -9,10 +43,144 @@ module Mail
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
+ # Get the oldest received email(s)
50
+ #
51
+ # Possible options:
52
+ # mailbox: mailbox to retrieve the oldest received email(s) from. The default is 'INBOX'.
53
+ # count: number of emails to retrieve. The default value is 1.
54
+ # order: order of emails returned. Possible values are :asc or :desc. Default value is :asc.
55
+ # keys: keywords for the imap SEARCH command. Can be either a string holding the entire
56
+ # search string or a single-dimension array of search keywords and arguments.
57
+ #
58
+ def first(options={}, &block)
59
+ options ||= {}
60
+ options[:what] = :first
61
+ options[:count] ||= 1
62
+ find(options, &block)
63
+ end
64
+
65
+ # Get the most recent received email(s)
66
+ #
67
+ # Possible options:
68
+ # mailbox: mailbox to retrieve the most recent received email(s) from. The default is 'INBOX'.
69
+ # count: number of emails to retrieve. The default value is 1.
70
+ # order: order of emails returned. Possible values are :asc or :desc. Default value is :asc.
71
+ # keys: keywords for the imap SEARCH command. Can be either a string holding the entire
72
+ # search string or a single-dimension array of search keywords and arguments.
73
+ #
74
+ def last(options={}, &block)
75
+ options ||= {}
76
+ options[:what] = :last
77
+ options[:count] ||= 1
78
+ find(options, &block)
79
+ end
80
+
81
+ # Get all emails.
82
+ #
83
+ # Possible options:
84
+ # mailbox: mailbox to retrieve all email(s) from. The default is 'INBOX'.
85
+ # count: number of emails to retrieve. The default value is 1.
86
+ # order: order of emails returned. Possible values are :asc or :desc. Default value is :asc.
87
+ # keys: keywords for the imap SEARCH command. Can be either a string holding the entire
88
+ # search string or a single-dimension array of search keywords and arguments.
89
+ #
90
+ def all(options={}, &block)
91
+ options ||= {}
92
+ options[:count] = :all
93
+ options[:keys] = 'ALL'
94
+ find(options, &block)
15
95
  end
16
96
 
97
+ # Find emails in a POP3 mailbox. Without any options, the 10 last received emails are returned.
98
+ #
99
+ # Possible options:
100
+ # mailbox: mailbox to search the email(s) in. The default is 'INBOX'.
101
+ # what: last or first emails. The default is :first.
102
+ # order: order of emails returned. Possible values are :asc or :desc. Default value is :asc.
103
+ # count: number of emails to retrieve. The default value is 10. A value of 1 returns an
104
+ # instance of Message, not an array of Message instances.
105
+ #
106
+ def find(options={}, &block)
107
+ options = validate_options(options)
108
+
109
+ start do |imap|
110
+ imap.select(options[:mailbox])
111
+
112
+ message_ids = imap.uid_search(options[:keys])
113
+ message_ids.reverse! if options[:what].to_sym == :last
114
+ message_ids = message_ids.first(options[:count]) if options[:count].is_a?(Integer)
115
+ message_ids.reverse! if (options[:what].to_sym == :last && options[:order].to_sym == :asc) ||
116
+ (options[:what].to_sym != :last && options[:order].to_sym == :desc)
117
+
118
+ if block_given?
119
+ message_ids.each do |message_id|
120
+ fetchdata = imap.uid_fetch(message_id, ['RFC822'])[0]
121
+
122
+ yield Mail.new(fetchdata.attr['RFC822'])
123
+ end
124
+ else
125
+ emails = []
126
+ message_ids.each do |message_id|
127
+ fetchdata = imap.uid_fetch(message_id, ['RFC822'])[0]
128
+
129
+ emails << Mail.new(fetchdata.attr['RFC822'])
130
+ end
131
+ emails.size == 1 && options[:count] == 1 ? emails.first : emails
132
+ end
133
+ end
134
+ end
135
+
136
+ # Delete all emails from a IMAP mailbox
137
+ def delete_all(mailbox='INBOX')
138
+ mailbox ||= 'INBOX'
139
+
140
+ start do |imap|
141
+ imap.select(mailbox)
142
+ imap.uid_search(['ALL']).each do |message_id|
143
+ imap.uid_store(message_id, "+FLAGS", [Net::IMAP::DELETED])
144
+ end
145
+ imap.expunge
146
+ end
147
+ end
148
+
149
+ # Returns the connection object of the retrievable (IMAP or POP3)
150
+ def connection(&block)
151
+ raise ArgumentError.new('Mail::Retrievable#connection takes a block') unless block_given?
152
+
153
+ start do |imap|
154
+ yield imap
155
+ end
156
+ end
157
+
158
+ private
159
+
160
+ # Set default options
161
+ def validate_options(options)
162
+ options ||= {}
163
+ options[:mailbox] ||= 'INBOX'
164
+ options[:count] ||= 10
165
+ options[:order] ||= :asc
166
+ options[:what] ||= :first
167
+ options[:keys] ||= 'ALL'
168
+ options
169
+ end
170
+
171
+ # Start an IMAP session and ensures that it will be closed in any case.
172
+ def start(config=Mail::Configuration.instance, &block)
173
+ raise ArgumentError.new("Mail::Retrievable#imap_start takes a block") unless block_given?
174
+
175
+ imap = Net::IMAP.new(settings[:address], settings[:port], settings[:enable_ssl], nil, false)
176
+ imap.login(settings[:user_name], settings[:password])
177
+
178
+ yield imap
179
+ ensure
180
+ if defined?(imap) && imap && !imap.disconnected?
181
+ imap.disconnect
182
+ end
183
+ end
184
+
17
185
  end
18
- end
186
+ end
@@ -89,12 +89,15 @@ module Mail
89
89
  # order: order of emails returned. Possible values are :asc or :desc. Default value is :asc.
90
90
  # count: number of emails to retrieve. The default value is 10. A value of 1 returns an
91
91
  # instance of Message, not an array of Message instances.
92
+ # delete_after_find: flag for whether to delete each retreived email after find. Default
93
+ # is false. Use #find_and_delete if you would like this to default to true.
92
94
  #
93
95
  def find(options = {}, &block)
94
96
  options = validate_options(options)
95
97
 
96
98
  start do |pop3|
97
99
  mails = pop3.mails
100
+ pop3.reset # Clears all "deleted" marks. This prevents non-explicit/accidental deletions due to server settings.
98
101
  mails.sort! { |m1, m2| m2.number <=> m1.number } if options[:what] == :last
99
102
  mails = mails.first(options[:count]) if options[:count].is_a? Integer
100
103
 
@@ -105,12 +108,16 @@ module Mail
105
108
 
106
109
  if block_given?
107
110
  mails.each do |mail|
108
- yield Mail.new(mail.pop)
111
+ new_message = Mail.new(mail.pop)
112
+ new_message.marked_for_delete = true if options[:delete_after_find]
113
+ yield new_message
114
+ mail.delete if options[:delete_after_find] && new_message.is_marked_for_delete? # Delete if still marked for delete
109
115
  end
110
116
  else
111
117
  emails = []
112
118
  mails.each do |mail|
113
119
  emails << Mail.new(mail.pop)
120
+ mail.delete if options[:delete_after_find]
114
121
  end
115
122
  emails.size == 1 && options[:count] == 1 ? emails.first : emails
116
123
  end
@@ -118,6 +125,23 @@ module Mail
118
125
  end
119
126
  end
120
127
 
128
+ # Find emails in a POP3 mailbox, and then deletes them. Without any options, the
129
+ # five last received emails are returned.
130
+ #
131
+ # Possible options:
132
+ # what: last or first emails. The default is :first.
133
+ # order: order of emails returned. Possible values are :asc or :desc. Default value is :asc.
134
+ # count: number of emails to retrieve. The default value is 10. A value of 1 returns an
135
+ # instance of Message, not an array of Message instances.
136
+ # delete_after_find: flag for whether to delete each retreived email after find. Default
137
+ # is true. Call #find if you would like this to default to false.
138
+ #
139
+ def find_and_delete(options = {}, &block)
140
+ options ||= {}
141
+ options[:delete_after_find] ||= true
142
+ find(options, &block)
143
+ end
144
+
121
145
  # Delete all emails from a POP3 server
122
146
  def delete_all
123
147
  start do |pop3|
@@ -127,6 +151,15 @@ module Mail
127
151
  end
128
152
  end
129
153
  end
154
+
155
+ # Returns the connection object of the retrievable (IMAP or POP3)
156
+ def connection(&block)
157
+ raise ArgumentError.new('Mail::Retrievable#connection takes a block') unless block_given?
158
+
159
+ start do |pop3|
160
+ yield pop3
161
+ end
162
+ end
130
163
 
131
164
  private
132
165
 
@@ -136,10 +169,13 @@ module Mail
136
169
  options[:count] ||= 10
137
170
  options[:order] ||= :asc
138
171
  options[:what] ||= :first
172
+ options[:delete_after_find] ||= false
139
173
  options
140
174
  end
141
175
 
142
- # Start a POP3 session and ensures that it will be closed in any case.
176
+ # Start a POP3 session and ensure that it will be closed in any case. Any messages
177
+ # marked for deletion via #find_and_delete or with the :delete_after_find option
178
+ # will be deleted when the session is closed.
143
179
  def start(config = Configuration.instance, &block)
144
180
  raise ArgumentError.new("Mail::Retrievable#pop3_start takes a block") unless block_given?
145
181
 
@@ -150,10 +186,9 @@ module Mail
150
186
  yield pop3
151
187
  ensure
152
188
  if defined?(pop3) && pop3 && pop3.started?
153
- pop3.reset # This clears all "deleted" marks from messages.
154
189
  pop3.finish
155
190
  end
156
191
  end
157
-
192
+
158
193
  end
159
- end
194
+ end
metadata CHANGED
@@ -1,14 +1,13 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: mail
3
3
  version: !ruby/object:Gem::Version
4
- hash: 101
4
+ hash: 9
5
5
  prerelease: false
6
6
  segments:
7
7
  - 2
8
8
  - 2
9
- - 6
10
- - 1
11
- version: 2.2.6.1
9
+ - 7
10
+ version: 2.2.7
12
11
  platform: ruby
13
12
  authors:
14
13
  - Mikel Lindsaar
@@ -16,11 +15,13 @@ autorequire:
16
15
  bindir: bin
17
16
  cert_chain: []
18
17
 
19
- date: 2010-09-13 00:00:00 +10:00
18
+ date: 2010-10-08 00:00:00 +11:00
20
19
  default_executable:
21
20
  dependencies:
22
21
  - !ruby/object:Gem::Dependency
23
- version_requirements: &id001 !ruby/object:Gem::Requirement
22
+ name: activesupport
23
+ prerelease: false
24
+ requirement: &id001 !ruby/object:Gem::Requirement
24
25
  none: false
25
26
  requirements:
26
27
  - - ">="
@@ -31,12 +32,12 @@ dependencies:
31
32
  - 3
32
33
  - 6
33
34
  version: 2.3.6
34
- requirement: *id001
35
35
  type: :runtime
36
- name: activesupport
37
- prerelease: false
36
+ version_requirements: *id001
38
37
  - !ruby/object:Gem::Dependency
39
- version_requirements: &id002 !ruby/object:Gem::Requirement
38
+ name: mime-types
39
+ prerelease: false
40
+ requirement: &id002 !ruby/object:Gem::Requirement
40
41
  none: false
41
42
  requirements:
42
43
  - - ">="
@@ -45,12 +46,12 @@ dependencies:
45
46
  segments:
46
47
  - 0
47
48
  version: "0"
48
- requirement: *id002
49
49
  type: :runtime
50
- name: mime-types
51
- prerelease: false
50
+ version_requirements: *id002
52
51
  - !ruby/object:Gem::Dependency
53
- version_requirements: &id003 !ruby/object:Gem::Requirement
52
+ name: treetop
53
+ prerelease: false
54
+ requirement: &id003 !ruby/object:Gem::Requirement
54
55
  none: false
55
56
  requirements:
56
57
  - - ">="
@@ -61,10 +62,8 @@ dependencies:
61
62
  - 4
62
63
  - 5
63
64
  version: 1.4.5
64
- requirement: *id003
65
65
  type: :runtime
66
- name: treetop
67
- prerelease: false
66
+ version_requirements: *id003
68
67
  description: A really Ruby Mail handler.
69
68
  email: raasdnil@gmail.com
70
69
  executables: []