Permalink
Browse files

Merge branch 'master' of http://github.com/fasta/mail into fasta-master

Conflicts:
	lib/mail/mail.rb
  • Loading branch information...
2 parents d7f918d + 54c9533 commit 170ffa334a259e5f2080cb07c62be939973e6cf6 @mikel mikel committed Sep 28, 2010
View
@@ -8,3 +8,4 @@ mail.tmproj
spec/fixtures/emails/failed_emails/
.rvmrc
*.rbc
+*.swp
@@ -53,6 +53,8 @@ def lookup_retriever_method(method)
Mail::POP3
when :pop3
Mail::POP3
+ when :imap
+ Mail::IMAP
else
method
end
@@ -64,4 +66,4 @@ def param_encode_language(value = nil)
end
-end
+end
View
@@ -187,6 +187,10 @@ def Mail.read_from_string(mail_as_string)
Mail.new(mail_as_string)
end
+ def Mail.connection(&block)
+ retriever_method.connection(&block)
+ end
+
# Initialize the observers and interceptors arrays
@@delivery_notification_observers = []
@@delivery_interceptors = []
@@ -1,5 +1,39 @@
+# encoding: utf-8
+
module Mail
+ # The IMAP retriever allows to get the last, first or all emails from a POP3 server.
+ # Each email retrieved (RFC2822) is given as an instance of +Message+.
+ #
+ # While being retrieved, emails can be yielded if a block is given.
+ #
+ # === Example of retrieving Emails from GMail:
+ #
+ # Mail.defaults do
+ # retriever_method :imap, { :address => "imap.googlemail.com",
+ # :port => 993,
+ # :user_name => '<username>',
+ # :password => '<password>',
+ # :enable_ssl => true }
+ # end
+ #
+ # Mail.all #=> Returns an array of all emails
+ # Mail.first #=> Returns the first unread email
+ # Mail.last #=> Returns the first unread email
+ #
+ # You can also pass options into Mail.find to locate an email in your imap mailbox
+ # with the following options:
+ #
+ # mailbox: name of the mailbox used for email retrieval. The default is 'INBOX'.
+ # what: last or first emails. The default is :first.
+ # order: order of emails returned. Possible values are :asc or :desc. Default value is :asc.
+ # count: number of emails to retrieve. The default value is 10. A value of 1 returns an
+ # instance of Message, not an array of Message instances.
+ #
+ # Mail.find(:what => :first, :count => 10, :order => :asc)
+ # #=> Returns the first 10 emails in ascending order
+ #
class IMAP
+ require 'net/imap'
def initialize(values)
self.settings = { :address => "localhost",
@@ -9,10 +43,144 @@ def initialize(values)
:authentication => nil,
:enable_ssl => false }.merge!(values)
end
-
- def IMAP.get_messages(&block)
- # To be implemented
+
+ attr_accessor :settings
+
+ # Get the oldest received email(s)
+ #
+ # Possible options:
+ # mailbox: mailbox to retrieve the oldest received email(s) from. The default is 'INBOX'.
+ # count: number of emails to retrieve. The default value is 1.
+ # order: order of emails returned. Possible values are :asc or :desc. Default value is :asc.
+ # keys: keywords for the imap SEARCH command. Can be either a string holding the entire
+ # search string or a single-dimension array of search keywords and arguments.
+ #
+ def first(options={}, &block)
+ options ||= {}
+ options[:what] = :first
+ options[:count] ||= 1
+ find(options, &block)
+ end
+
+ # Get the most recent received email(s)
+ #
+ # Possible options:
+ # mailbox: mailbox to retrieve the most recent received email(s) from. The default is 'INBOX'.
+ # count: number of emails to retrieve. The default value is 1.
+ # order: order of emails returned. Possible values are :asc or :desc. Default value is :asc.
+ # keys: keywords for the imap SEARCH command. Can be either a string holding the entire
+ # search string or a single-dimension array of search keywords and arguments.
+ #
+ def last(options={}, &block)
+ options ||= {}
+ options[:what] = :last
+ options[:count] ||= 1
+ find(options, &block)
+ end
+
+ # Get all emails.
+ #
+ # Possible options:
+ # mailbox: mailbox to retrieve all email(s) from. The default is 'INBOX'.
+ # count: number of emails to retrieve. The default value is 1.
+ # order: order of emails returned. Possible values are :asc or :desc. Default value is :asc.
+ # keys: keywords for the imap SEARCH command. Can be either a string holding the entire
+ # search string or a single-dimension array of search keywords and arguments.
+ #
+ def all(options={}, &block)
+ options ||= {}
+ options[:count] = :all
+ options[:keys] = 'ALL'
+ find(options, &block)
end
+ # Find emails in a POP3 mailbox. Without any options, the 10 last received emails are returned.
+ #
+ # Possible options:
+ # mailbox: mailbox to search the email(s) in. The default is 'INBOX'.
+ # what: last or first emails. The default is :first.
+ # order: order of emails returned. Possible values are :asc or :desc. Default value is :asc.
+ # count: number of emails to retrieve. The default value is 10. A value of 1 returns an
+ # instance of Message, not an array of Message instances.
+ #
+ def find(options={}, &block)
+ options = validate_options(options)
+
+ start do |imap|
+ imap.select(options[:mailbox])
+
+ message_ids = imap.uid_search(options[:keys])
+ message_ids.reverse! if options[:what].to_sym == :last
+ message_ids = message_ids.first(options[:count]) if options[:count].is_a?(Integer)
+ message_ids.reverse! if (options[:what].to_sym == :last && options[:order].to_sym == :asc) ||
+ (options[:what].to_sym != :last && options[:order].to_sym == :desc)
+
+ if block_given?
+ message_ids.each do |message_id|
+ fetchdata = imap.uid_fetch(message_id, ['RFC822'])[0]
+
+ yield Mail.new(fetchdata.attr['RFC822'])
+ end
+ else
+ emails = []
+ message_ids.each do |message_id|
+ fetchdata = imap.uid_fetch(message_id, ['RFC822'])[0]
+
+ emails << Mail.new(fetchdata.attr['RFC822'])
+ end
+ emails.size == 1 && options[:count] == 1 ? emails.first : emails
+ end
+ end
+ end
+
+ # Delete all emails from a IMAP mailbox
+ def delete_all(mailbox='INBOX')
+ mailbox ||= 'INBOX'
+
+ start do |imap|
+ imap.select(mailbox)
+ imap.uid_search(['ALL']).each do |message_id|
+ imap.uid_store(message_id, "+FLAGS", [Net::IMAP::DELETED])
+ end
+ imap.expunge
+ end
+ end
+
+ # Returns the connection object of the retrievable (IMAP or POP3)
+ def connection(&block)
+ raise ArgumentError.new('Mail::Retrievable#connection takes a block') unless block_given?
+
+ start do |imap|
+ yield imap
+ end
+ end
+
+ private
+
+ # Set default options
+ def validate_options(options)
+ options ||= {}
+ options[:mailbox] ||= 'INBOX'
+ options[:count] ||= 10
+ options[:order] ||= :asc
+ options[:what] ||= :first
+ options[:keys] ||= 'ALL'
+ options
+ end
+
+ # Start an IMAP session and ensures that it will be closed in any case.
+ def start(config=Mail::Configuration.instance, &block)
+ raise ArgumentError.new("Mail::Retrievable#imap_start takes a block") unless block_given?
+
+ imap = Net::IMAP.new(settings[:address], settings[:port], settings[:enable_ssl], nil, false)
+ imap.login(settings[:user_name], settings[:password])
+
+ yield imap
+ ensure
+ if defined?(imap) && imap && !imap.disconnected?
+ imap.disconnect
+ end
+ end
+
end
-end
+end
@@ -151,6 +151,15 @@ def delete_all
end
end
end
+
+ # Returns the connection object of the retrievable (IMAP or POP3)
+ def connection(&block)
+ raise ArgumentError.new('Mail::Retrievable#connection takes a block') unless block_given?
+
+ start do |pop3|
+ yield pop3
+ end
+ end
private
@@ -182,4 +191,4 @@ def start(config = Configuration.instance, &block)
end
end
-end
+end
Oops, something went wrong.

0 comments on commit 170ffa3

Please sign in to comment.