dball-mail 2.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.
Files changed (122) hide show
  1. data/CHANGELOG.rdoc +459 -0
  2. data/README.rdoc +582 -0
  3. data/Rakefile +66 -0
  4. data/TODO.rdoc +9 -0
  5. data/lib/VERSION +4 -0
  6. data/lib/mail/attachments_list.rb +105 -0
  7. data/lib/mail/body.rb +286 -0
  8. data/lib/mail/configuration.rb +71 -0
  9. data/lib/mail/core_extensions/nil.rb +11 -0
  10. data/lib/mail/core_extensions/string.rb +27 -0
  11. data/lib/mail/elements/address.rb +306 -0
  12. data/lib/mail/elements/address_list.rb +74 -0
  13. data/lib/mail/elements/content_disposition_element.rb +30 -0
  14. data/lib/mail/elements/content_location_element.rb +25 -0
  15. data/lib/mail/elements/content_transfer_encoding_element.rb +24 -0
  16. data/lib/mail/elements/content_type_element.rb +35 -0
  17. data/lib/mail/elements/date_time_element.rb +26 -0
  18. data/lib/mail/elements/envelope_from_element.rb +34 -0
  19. data/lib/mail/elements/message_ids_element.rb +29 -0
  20. data/lib/mail/elements/mime_version_element.rb +26 -0
  21. data/lib/mail/elements/phrase_list.rb +21 -0
  22. data/lib/mail/elements/received_element.rb +30 -0
  23. data/lib/mail/elements.rb +14 -0
  24. data/lib/mail/encodings/7bit.rb +31 -0
  25. data/lib/mail/encodings/8bit.rb +31 -0
  26. data/lib/mail/encodings/base64.rb +33 -0
  27. data/lib/mail/encodings/binary.rb +31 -0
  28. data/lib/mail/encodings/quoted_printable.rb +38 -0
  29. data/lib/mail/encodings/transfer_encoding.rb +58 -0
  30. data/lib/mail/encodings.rb +268 -0
  31. data/lib/mail/envelope.rb +35 -0
  32. data/lib/mail/field.rb +223 -0
  33. data/lib/mail/field_list.rb +33 -0
  34. data/lib/mail/fields/bcc_field.rb +56 -0
  35. data/lib/mail/fields/cc_field.rb +55 -0
  36. data/lib/mail/fields/comments_field.rb +41 -0
  37. data/lib/mail/fields/common/address_container.rb +16 -0
  38. data/lib/mail/fields/common/common_address.rb +125 -0
  39. data/lib/mail/fields/common/common_date.rb +42 -0
  40. data/lib/mail/fields/common/common_field.rb +50 -0
  41. data/lib/mail/fields/common/common_message_id.rb +44 -0
  42. data/lib/mail/fields/common/parameter_hash.rb +58 -0
  43. data/lib/mail/fields/content_description_field.rb +19 -0
  44. data/lib/mail/fields/content_disposition_field.rb +69 -0
  45. data/lib/mail/fields/content_id_field.rb +63 -0
  46. data/lib/mail/fields/content_location_field.rb +42 -0
  47. data/lib/mail/fields/content_transfer_encoding_field.rb +50 -0
  48. data/lib/mail/fields/content_type_field.rb +198 -0
  49. data/lib/mail/fields/date_field.rb +55 -0
  50. data/lib/mail/fields/from_field.rb +55 -0
  51. data/lib/mail/fields/in_reply_to_field.rb +55 -0
  52. data/lib/mail/fields/keywords_field.rb +44 -0
  53. data/lib/mail/fields/message_id_field.rb +83 -0
  54. data/lib/mail/fields/mime_version_field.rb +53 -0
  55. data/lib/mail/fields/optional_field.rb +13 -0
  56. data/lib/mail/fields/received_field.rb +67 -0
  57. data/lib/mail/fields/references_field.rb +55 -0
  58. data/lib/mail/fields/reply_to_field.rb +55 -0
  59. data/lib/mail/fields/resent_bcc_field.rb +55 -0
  60. data/lib/mail/fields/resent_cc_field.rb +55 -0
  61. data/lib/mail/fields/resent_date_field.rb +35 -0
  62. data/lib/mail/fields/resent_from_field.rb +55 -0
  63. data/lib/mail/fields/resent_message_id_field.rb +34 -0
  64. data/lib/mail/fields/resent_sender_field.rb +62 -0
  65. data/lib/mail/fields/resent_to_field.rb +55 -0
  66. data/lib/mail/fields/return_path_field.rb +64 -0
  67. data/lib/mail/fields/sender_field.rb +67 -0
  68. data/lib/mail/fields/structured_field.rb +51 -0
  69. data/lib/mail/fields/subject_field.rb +16 -0
  70. data/lib/mail/fields/to_field.rb +55 -0
  71. data/lib/mail/fields/unstructured_field.rb +179 -0
  72. data/lib/mail/fields.rb +35 -0
  73. data/lib/mail/header.rb +264 -0
  74. data/lib/mail/mail.rb +255 -0
  75. data/lib/mail/message.rb +1972 -0
  76. data/lib/mail/network/delivery_methods/file_delivery.rb +40 -0
  77. data/lib/mail/network/delivery_methods/sendmail.rb +62 -0
  78. data/lib/mail/network/delivery_methods/smtp.rb +136 -0
  79. data/lib/mail/network/delivery_methods/test_mailer.rb +40 -0
  80. data/lib/mail/network/retriever_methods/imap.rb +213 -0
  81. data/lib/mail/network/retriever_methods/pop3.rb +194 -0
  82. data/lib/mail/network/retriever_methods/test_retriever.rb +31 -0
  83. data/lib/mail/network.rb +10 -0
  84. data/lib/mail/parsers/address_lists.rb +64 -0
  85. data/lib/mail/parsers/address_lists.treetop +19 -0
  86. data/lib/mail/parsers/content_disposition.rb +535 -0
  87. data/lib/mail/parsers/content_disposition.treetop +46 -0
  88. data/lib/mail/parsers/content_location.rb +139 -0
  89. data/lib/mail/parsers/content_location.treetop +20 -0
  90. data/lib/mail/parsers/content_transfer_encoding.rb +162 -0
  91. data/lib/mail/parsers/content_transfer_encoding.treetop +20 -0
  92. data/lib/mail/parsers/content_type.rb +967 -0
  93. data/lib/mail/parsers/content_type.treetop +68 -0
  94. data/lib/mail/parsers/date_time.rb +114 -0
  95. data/lib/mail/parsers/date_time.treetop +11 -0
  96. data/lib/mail/parsers/envelope_from.rb +194 -0
  97. data/lib/mail/parsers/envelope_from.treetop +32 -0
  98. data/lib/mail/parsers/message_ids.rb +45 -0
  99. data/lib/mail/parsers/message_ids.treetop +15 -0
  100. data/lib/mail/parsers/mime_version.rb +144 -0
  101. data/lib/mail/parsers/mime_version.treetop +19 -0
  102. data/lib/mail/parsers/phrase_lists.rb +45 -0
  103. data/lib/mail/parsers/phrase_lists.treetop +15 -0
  104. data/lib/mail/parsers/received.rb +71 -0
  105. data/lib/mail/parsers/received.treetop +11 -0
  106. data/lib/mail/parsers/rfc2045.rb +464 -0
  107. data/lib/mail/parsers/rfc2045.treetop +36 -0
  108. data/lib/mail/parsers/rfc2822.rb +5318 -0
  109. data/lib/mail/parsers/rfc2822.treetop +410 -0
  110. data/lib/mail/parsers/rfc2822_obsolete.rb +3757 -0
  111. data/lib/mail/parsers/rfc2822_obsolete.treetop +241 -0
  112. data/lib/mail/part.rb +116 -0
  113. data/lib/mail/parts_list.rb +43 -0
  114. data/lib/mail/patterns.rb +34 -0
  115. data/lib/mail/utilities.rb +211 -0
  116. data/lib/mail/version.rb +24 -0
  117. data/lib/mail/version_specific/ruby_1_8.rb +97 -0
  118. data/lib/mail/version_specific/ruby_1_9.rb +87 -0
  119. data/lib/mail.rb +80 -0
  120. data/lib/tasks/corpus.rake +125 -0
  121. data/lib/tasks/treetop.rake +10 -0
  122. metadata +255 -0
@@ -0,0 +1,40 @@
1
+ module Mail
2
+
3
+ # FileDelivery class delivers emails into multiple files based on the destination
4
+ # address. Each file is appended to if it already exists.
5
+ #
6
+ # So if you have an email going to fred@test, bob@test, joe@anothertest, and you
7
+ # set your location path to /path/to/mails then FileDelivery will create the directory
8
+ # if it does not exist, and put one copy of the email in three files, called
9
+ # "fred@test", "bob@test" and "joe@anothertest"
10
+ #
11
+ # Make sure the path you specify with :location is writable by the Ruby process
12
+ # running Mail.
13
+ class FileDelivery
14
+
15
+ if RUBY_VERSION >= '1.9.1'
16
+ require 'fileutils'
17
+ else
18
+ require 'ftools'
19
+ end
20
+
21
+ def initialize(values)
22
+ self.settings = { :location => './mails' }.merge!(values)
23
+ end
24
+
25
+ attr_accessor :settings
26
+
27
+ def deliver!(mail)
28
+ if ::File.respond_to?(:makedirs)
29
+ ::File.makedirs settings[:location]
30
+ else
31
+ ::FileUtils.mkdir_p settings[:location]
32
+ end
33
+
34
+ mail.destinations.uniq.each do |to|
35
+ ::File.open(::File.join(settings[:location], to), 'a') { |f| "#{f.write(mail.encoded)}\r\n\r\n" }
36
+ end
37
+ end
38
+
39
+ end
40
+ end
@@ -0,0 +1,62 @@
1
+ module Mail
2
+ # A delivery method implementation which sends via sendmail.
3
+ #
4
+ # To use this, first find out where the sendmail binary is on your computer,
5
+ # if you are on a mac or unix box, it is usually in /usr/sbin/sendmail, this will
6
+ # be your sendmail location.
7
+ #
8
+ # Mail.defaults do
9
+ # delivery_method :sendmail
10
+ # end
11
+ #
12
+ # Or if your sendmail binary is not at '/usr/sbin/sendmail'
13
+ #
14
+ # Mail.defaults do
15
+ # delivery_method :sendmail, :location => '/absolute/path/to/your/sendmail'
16
+ # end
17
+ #
18
+ # Then just deliver the email as normal:
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 Sendmail
38
+
39
+ def initialize(values)
40
+ self.settings = { :location => '/usr/sbin/sendmail',
41
+ :arguments => '-i -t' }.merge(values)
42
+ end
43
+
44
+ attr_accessor :settings
45
+
46
+ def deliver!(mail)
47
+ envelope_from = mail.return_path || mail.sender || mail.from_addrs.first
48
+ return_path = "-f \"#{envelope_from}\"" if envelope_from
49
+
50
+ arguments = [settings[:arguments], return_path].compact.join(" ")
51
+
52
+ Sendmail.call(settings[:location], arguments, mail.destinations.join(" "), mail)
53
+ end
54
+
55
+ def Sendmail.call(path, arguments, destinations, mail)
56
+ IO.popen("#{path} #{arguments} #{destinations}", "w+") do |io|
57
+ io.puts mail.encoded.to_lf
58
+ io.flush
59
+ end
60
+ end
61
+ end
62
+ end
@@ -0,0 +1,136 @@
1
+ module Mail
2
+ # == Sending Email with SMTP
3
+ #
4
+ # Mail allows you to send emails using SMTP. This is done by wrapping Net::SMTP in
5
+ # an easy to use manner.
6
+ #
7
+ # === Sending via SMTP server on Localhost
8
+ #
9
+ # Sending locally (to a postfix or sendmail server running on localhost) requires
10
+ # no special setup. Just to Mail.deliver &block or message.deliver! and it will
11
+ # be sent in this method.
12
+ #
13
+ # === Sending via MobileMe
14
+ #
15
+ # Mail.defaults do
16
+ # delivery_method :smtp, { :address => "smtp.me.com",
17
+ # :port => 587,
18
+ # :domain => 'your.host.name',
19
+ # :user_name => '<username>',
20
+ # :password => '<password>',
21
+ # :authentication => 'plain',
22
+ # :enable_starttls_auto => true }
23
+ # end
24
+ #
25
+ # === Sending via GMail
26
+ #
27
+ # Mail.defaults do
28
+ # delivery_method :smtp, { :address => "smtp.gmail.com",
29
+ # :port => 587,
30
+ # :domain => 'your.host.name',
31
+ # :user_name => '<username>',
32
+ # :password => '<password>',
33
+ # :authentication => 'plain',
34
+ # :enable_starttls_auto => true }
35
+ # end
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
+ #
49
+ # === Others
50
+ #
51
+ # Feel free to send me other examples that were tricky
52
+ #
53
+ # === Delivering the email
54
+ #
55
+ # Once you have the settings right, sending the email is done by:
56
+ #
57
+ # Mail.deliver do
58
+ # to 'mikel@test.lindsaar.net'
59
+ # from 'ada@test.lindsaar.net'
60
+ # subject 'testing sendmail'
61
+ # body 'testing sendmail'
62
+ # end
63
+ #
64
+ # Or by calling deliver on a Mail message
65
+ #
66
+ # mail = Mail.new do
67
+ # to 'mikel@test.lindsaar.net'
68
+ # from 'ada@test.lindsaar.net'
69
+ # subject 'testing sendmail'
70
+ # body 'testing sendmail'
71
+ # end
72
+ #
73
+ # mail.deliver!
74
+ class SMTP
75
+
76
+ def initialize(values)
77
+ self.settings = { :address => "localhost",
78
+ :port => 25,
79
+ :domain => 'localhost.localdomain',
80
+ :user_name => nil,
81
+ :password => nil,
82
+ :authentication => nil,
83
+ :enable_starttls_auto => true,
84
+ :openssl_verify_mode => nil
85
+ }.merge!(values)
86
+ end
87
+
88
+ attr_accessor :settings
89
+
90
+ # Send the message via SMTP.
91
+ # The from and to attributes are optional. If not set, they are retrieve from the Message.
92
+ def deliver!(mail)
93
+
94
+ # Set the envelope from to be either the return-path, the sender or the first from address
95
+ envelope_from = mail.return_path || mail.sender || mail.from_addrs.first
96
+ if envelope_from.blank?
97
+ raise ArgumentError.new('A sender (Return-Path, Sender or From) required to send a message')
98
+ end
99
+
100
+ destinations ||= mail.destinations if mail.respond_to?(:destinations) && mail.destinations
101
+ if destinations.blank?
102
+ raise ArgumentError.new('At least one recipient (To, Cc or Bcc) is required to send a message')
103
+ end
104
+
105
+ message ||= mail.encoded if mail.respond_to?(:encoded)
106
+ if message.blank?
107
+ raise ArgumentError.new('A encoded content is required to send a message')
108
+ end
109
+
110
+ smtp = Net::SMTP.new(settings[:address], settings[:port])
111
+ if settings[: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
125
+ end
126
+
127
+ smtp.start(settings[:domain], settings[:user_name], settings[:password], settings[:authentication]) do |smtp|
128
+ smtp.sendmail(message, envelope_from, destinations)
129
+ end
130
+
131
+ self
132
+ end
133
+
134
+
135
+ end
136
+ end
@@ -0,0 +1,40 @@
1
+ module Mail
2
+ # The TestMailer is a bare bones mailer that does nothing. It is useful
3
+ # when you are testing.
4
+ #
5
+ # It also provides a template of the minimum methods you require to implement
6
+ # if you want to make a custom mailer for Mail
7
+ class TestMailer
8
+
9
+ # Provides a store of all the emails sent with the TestMailer so you can check them.
10
+ def TestMailer.deliveries
11
+ @@deliveries ||= []
12
+ end
13
+
14
+ # Allows you to over write the default deliveries store from an array to some
15
+ # other object. If you just want to clear the store,
16
+ # call TestMailer.deliveries.clear.
17
+ #
18
+ # If you place another object here, please make sure it responds to:
19
+ #
20
+ # * << (message)
21
+ # * clear
22
+ # * length
23
+ # * size
24
+ # * and other common Array methods
25
+ def TestMailer.deliveries=(val)
26
+ @@deliveries = val
27
+ end
28
+
29
+ def initialize(values)
30
+ @settings = {}
31
+ end
32
+
33
+ attr_accessor :settings
34
+
35
+ def deliver!(mail)
36
+ Mail::TestMailer.deliveries << mail
37
+ end
38
+
39
+ end
40
+ end
@@ -0,0 +1,213 @@
1
+ # encoding: utf-8
2
+
3
+ module Mail
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
36
+ require 'net/imap'
37
+
38
+ def initialize(values)
39
+ self.settings = { :address => "localhost",
40
+ :port => 110,
41
+ :user_name => nil,
42
+ :password => nil,
43
+ :authentication => nil,
44
+ :enable_ssl => false }.merge!(values)
45
+ end
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)
95
+ end
96
+
97
+ # Find emails in a IMAP 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
+ # delete_after_find: flag for whether to delete each retreived email after find. Default
106
+ # is false. Use #find_and_delete if you would like this to default to true.
107
+ #
108
+ def find(options={}, &block)
109
+ options = validate_options(options)
110
+
111
+ start do |imap|
112
+ imap.select(options[:mailbox])
113
+
114
+ message_ids = imap.uid_search(options[:keys])
115
+ message_ids.reverse! if options[:what].to_sym == :last
116
+ message_ids = message_ids.first(options[:count]) if options[:count].is_a?(Integer)
117
+ message_ids.reverse! if (options[:what].to_sym == :last && options[:order].to_sym == :asc) ||
118
+ (options[:what].to_sym != :last && options[:order].to_sym == :desc)
119
+
120
+ if block_given?
121
+ message_ids.each do |message_id|
122
+ fetchdata = imap.uid_fetch(message_id, ['RFC822'])[0]
123
+ new_message = Mail.new(fetchdata.attr['RFC822'])
124
+ new_message.mark_for_delete = true if options[:delete_after_find]
125
+ yield new_message
126
+ imap.uid_store(message_id, "+FLAGS", [Net::IMAP::DELETED]) if options[:delete_after_find] && new_message.is_marked_for_delete?
127
+ end
128
+ imap.expunge if options[:delete_after_find]
129
+ else
130
+ emails = []
131
+ message_ids.each do |message_id|
132
+ fetchdata = imap.uid_fetch(message_id, ['RFC822'])[0]
133
+ emails << Mail.new(fetchdata.attr['RFC822'])
134
+ imap.uid_store(message_id, "+FLAGS", [Net::IMAP::DELETED]) if options[:delete_after_find]
135
+ end
136
+ imap.expunge if options[:delete_after_find]
137
+ emails.size == 1 && options[:count] == 1 ? emails.first : emails
138
+ end
139
+ end
140
+ end
141
+
142
+ # Find emails in a IMAP mailbox, and then deletes them. Without any options, the
143
+ # five last received emails are returned.
144
+ #
145
+ # Possible options:
146
+ # what: last or first emails. The default is :first.
147
+ # order: order of emails returned. Possible values are :asc or :desc. Default value is :asc.
148
+ # count: number of emails to retrieve. The default value is 10. A value of 1 returns an
149
+ # instance of Message, not an array of Message instances.
150
+ # delete_after_find: flag for whether to delete each retreived email after find. Default
151
+ # is true. Use #find_and_delete if you would like this to default to false.
152
+ #
153
+ def find_and_delete(options = {}, &block)
154
+ options ||= {}
155
+ options[:delete_after_find] ||= true
156
+ find(options, &block)
157
+ end
158
+
159
+ # Delete all emails from a IMAP mailbox
160
+ def delete_all(mailbox='INBOX')
161
+ mailbox ||= 'INBOX'
162
+ mailbox = Net::IMAP.encode_utf7(mailbox)
163
+
164
+ start do |imap|
165
+ imap.select(mailbox)
166
+ imap.uid_search(['ALL']).each do |message_id|
167
+ imap.uid_store(message_id, "+FLAGS", [Net::IMAP::DELETED])
168
+ end
169
+ imap.expunge
170
+ end
171
+ end
172
+
173
+ # Returns the connection object of the retrievable (IMAP or POP3)
174
+ def connection(&block)
175
+ raise ArgumentError.new('Mail::Retrievable#connection takes a block') unless block_given?
176
+
177
+ start do |imap|
178
+ yield imap
179
+ end
180
+ end
181
+
182
+ private
183
+
184
+ # Set default options
185
+ def validate_options(options)
186
+ options ||= {}
187
+ options[:mailbox] ||= 'INBOX'
188
+ options[:count] ||= 10
189
+ options[:order] ||= :asc
190
+ options[:what] ||= :first
191
+ options[:keys] ||= 'ALL'
192
+ options[:delete_after_find] ||= false
193
+ options[:mailbox] = Net::IMAP.encode_utf7(options[:mailbox])
194
+
195
+ options
196
+ end
197
+
198
+ # Start an IMAP session and ensures that it will be closed in any case.
199
+ def start(config=Mail::Configuration.instance, &block)
200
+ raise ArgumentError.new("Mail::Retrievable#imap_start takes a block") unless block_given?
201
+
202
+ imap = Net::IMAP.new(settings[:address], settings[:port], settings[:enable_ssl], nil, false)
203
+ imap.login(settings[:user_name], settings[:password])
204
+
205
+ yield imap
206
+ ensure
207
+ if defined?(imap) && imap && !imap.disconnected?
208
+ imap.disconnect
209
+ end
210
+ end
211
+
212
+ end
213
+ end
@@ -0,0 +1,194 @@
1
+ # encoding: utf-8
2
+
3
+ module Mail
4
+ # The Pop3 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 :pop3, { :address => "pop.gmail.com",
13
+ # :port => 995,
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 pop mailbox
24
+ # with the following options:
25
+ #
26
+ # what: last or first emails. The default is :first.
27
+ # order: order of emails returned. Possible values are :asc or :desc. Default value is :asc.
28
+ # count: number of emails to retrieve. The default value is 10. A value of 1 returns an
29
+ # instance of Message, not an array of Message instances.
30
+ #
31
+ # Mail.find(:what => :first, :count => 10, :order => :asc)
32
+ # #=> Returns the first 10 emails in ascending order
33
+ #
34
+ class POP3
35
+ require 'net/pop'
36
+
37
+ def initialize(values)
38
+ self.settings = { :address => "localhost",
39
+ :port => 110,
40
+ :user_name => nil,
41
+ :password => nil,
42
+ :authentication => nil,
43
+ :enable_ssl => false }.merge!(values)
44
+ end
45
+
46
+ attr_accessor :settings
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
+ # Find emails in a POP3 mailbox. Without any options, the 5 last received emails are returned.
86
+ #
87
+ # Possible options:
88
+ # what: last or first emails. The default is :first.
89
+ # order: order of emails returned. Possible values are :asc or :desc. Default value is :asc.
90
+ # count: number of emails to retrieve. The default value is 10. A value of 1 returns an
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.
94
+ #
95
+ def find(options = {}, &block)
96
+ options = validate_options(options)
97
+
98
+ start do |pop3|
99
+ mails = pop3.mails
100
+ pop3.reset # Clears all "deleted" marks. This prevents non-explicit/accidental deletions due to server settings.
101
+ mails.sort! { |m1, m2| m2.number <=> m1.number } if options[:what] == :last
102
+ mails = mails.first(options[:count]) if options[:count].is_a? Integer
103
+
104
+ if options[:what].to_sym == :last && options[:order].to_sym == :desc ||
105
+ options[:what].to_sym == :first && options[:order].to_sym == :asc ||
106
+ mails.reverse!
107
+ end
108
+
109
+ if block_given?
110
+ mails.each do |mail|
111
+ new_message = Mail.new(mail.pop)
112
+ new_message.mark_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
115
+ end
116
+ else
117
+ emails = []
118
+ mails.each do |mail|
119
+ emails << Mail.new(mail.pop)
120
+ mail.delete if options[:delete_after_find]
121
+ end
122
+ emails.size == 1 && options[:count] == 1 ? emails.first : emails
123
+ end
124
+
125
+ end
126
+ end
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
+
145
+ # Delete all emails from a POP3 server
146
+ def delete_all
147
+ start do |pop3|
148
+ unless pop3.mails.empty?
149
+ pop3.delete_all
150
+ pop3.finish
151
+ end
152
+ end
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
163
+
164
+ private
165
+
166
+ # Set default options
167
+ def validate_options(options)
168
+ options ||= {}
169
+ options[:count] ||= 10
170
+ options[:order] ||= :asc
171
+ options[:what] ||= :first
172
+ options[:delete_after_find] ||= false
173
+ options
174
+ end
175
+
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.
179
+ def start(config = Configuration.instance, &block)
180
+ raise ArgumentError.new("Mail::Retrievable#pop3_start takes a block") unless block_given?
181
+
182
+ pop3 = Net::POP3.new(settings[:address], settings[:port], isapop = false)
183
+ pop3.enable_ssl(verify = OpenSSL::SSL::VERIFY_NONE) if settings[:enable_ssl]
184
+ pop3.start(settings[:user_name], settings[:password])
185
+
186
+ yield pop3
187
+ ensure
188
+ if defined?(pop3) && pop3 && pop3.started?
189
+ pop3.finish
190
+ end
191
+ end
192
+
193
+ end
194
+ end