gmail_oauth 0.1.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.
data/.gitignore ADDED
@@ -0,0 +1,25 @@
1
+ ## MAC OS
2
+ .DS_Store
3
+
4
+ ## TEXTMATE
5
+ *.tmproj
6
+ tmtags
7
+
8
+ ## EMACS
9
+ *~
10
+ \#*
11
+ .\#*
12
+
13
+ ## VIM
14
+ *.swp
15
+
16
+ ## PROJECT::GENERAL
17
+ coverage
18
+ rdoc
19
+ pkg
20
+
21
+ ## PROJECT::SPECIFIC
22
+ *.rdb
23
+
24
+ ## Test Account details
25
+ spec/account.yml
data/CHANGELOG.md ADDED
@@ -0,0 +1,5 @@
1
+ # gmail_oauth gem changelog
2
+
3
+ ## 0.1 / 2010-12-13
4
+
5
+ * Birthday of OAuth version from https://github.com/nu7hatch/gmail
data/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ Copyrignt (c) 2010 Kriss 'nu7hatch' Kowalik
2
+ Copyright (c) 2009-2010 BehindLogic
3
+
4
+ Permission is hereby granted, free of charge, to any person obtaining
5
+ a copy of this software and associated documentation files (the
6
+ "Software"), to deal in the Software without restriction, including
7
+ without limitation the rights to use, copy, modify, merge, publish,
8
+ distribute, sublicense, and/or sell copies of the Software, and to
9
+ permit persons to whom the Software is furnished to do so, subject to
10
+ the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be
13
+ included in all copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
16
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
17
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
18
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
19
+ LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
20
+ OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
21
+ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
data/README.md ADDED
@@ -0,0 +1,257 @@
1
+ # GMail for Ruby
2
+
3
+ I changed the auth method to Oauth, using Nicolas Fouché's [gmail_xoauth](https://github.com/nfo/gmail_xoauth).
4
+
5
+ To use it you must produce your own token and secret. You can follow an example of how to do it by [Nicolas Fouché](https://github.com/nfo/gmail-oauth-sinatra).
6
+
7
+ THIS IS NOT TESTED.
8
+
9
+ ###To Do
10
+ * Write specs (I know, I know)
11
+
12
+ A Rubyesque interface to Google's GMail with Oauth, with all the tools you'll need. Search,
13
+ read and send multipart emails, archive, mark as read/unread, delete emails,
14
+ and manage labels.
15
+
16
+ It's based on Kriss 'nu7hatch' Kowalik gmail gem. This version has oauth login and does not require username and password from users.
17
+
18
+ ## Author(s)
19
+
20
+ * [Kriss 'nu7hatch' Kowalik](http://github.com/nu7hatch)
21
+ * [Daniel Parker of BehindLogic.com](http://github.com/dcparker)
22
+
23
+ Extra thanks for specific feature contributions from:
24
+
25
+ * [Arthur Chiu](http://github.com/achiu)
26
+ * [Justin Perkins](http://github.com/justinperkins)
27
+ * [Mikkel Malmberg](http://github.com/mikker)
28
+ * [Julien Blanchard](http://github.com/julienXX)
29
+ * [Federico Galassi](http://github.com/fgalassi)
30
+
31
+ ## Installation
32
+
33
+ You can install it easy using rubygems:
34
+
35
+ sudo gem install gmail_oauth
36
+
37
+ Or install it manualy:
38
+
39
+ git clone git://github.com/stefanobernardi/gmail_oauth.git
40
+ cd gmail
41
+ rake install
42
+
43
+ To install gmail gem you have to met following requirements (with rubygems all
44
+ will be installed automatically):
45
+
46
+ * mail
47
+ * mime
48
+ * gmail_xoauth
49
+ * smpt_tls (Ruby < 1.8.7)
50
+
51
+ ## Features
52
+
53
+ * Search emails
54
+ * Read emails (handles attachments)
55
+ * Emails: label, archive, delete, mark as read/unread/spam, star
56
+ * Manage labels
57
+ * Create and send multipart email messages in plaintext and/or html, with inline
58
+ images and attachments
59
+ * Utilizes Gmail's IMAP & SMTP, MIME-type detection and parses and generates
60
+ MIME properly.
61
+
62
+ ## Basic usage
63
+
64
+ First of all require the `gmail-oauth` library.
65
+
66
+ require 'gmail_oauth'
67
+
68
+ ### Authenticating gmail sessions
69
+
70
+ This will you automatically log in to your account.
71
+
72
+ gmail = Gmail.connect(email, token, secret, consumer_key, consumer_secret)
73
+ # play with your gmail...
74
+ gmail.logout
75
+
76
+ If you pass a block, the session will be passed into the block, and the session
77
+ will be logged out after the block is executed.
78
+
79
+ Gmail.connect(email, token, secret, consumer_key, consumer_secret) do |gmail|
80
+ # play with your gmail...
81
+ end
82
+
83
+ Examples above are "quiet", it means that it will not raise any errors when
84
+ session couldn't be started (eg. because of connection error or invalid
85
+ authorization data). You can use connection which handles errors raising:
86
+
87
+ Gmail.connect!(email, token, secret, consumer_key, consumer_secret)
88
+ Gmail.connect!(email, token, secret, consumer_key, consumer_secret) {|gmail| ... play with gmail ... }
89
+
90
+ You can also check if you are logged in at any time:
91
+
92
+ Gmail.connect(email, token, secret, consumer_key, consumer_secret) do |gmail|
93
+ gmail.logged_in?
94
+ end
95
+
96
+ ### Counting and gathering emails
97
+
98
+ Get counts for messages in the inbox:
99
+
100
+ gmail.inbox.count
101
+ gmail.inbox.count(:unread)
102
+ gmail.inbox.count(:read)
103
+
104
+ Count with some criteria:
105
+
106
+ gmail.inbox.count(:after => Date.parse("2010-02-20"), :before => Date.parse("2010-03-20"))
107
+ gmail.inbox.count(:on => Date.parse("2010-04-15"))
108
+ gmail.inbox.count(:from => "myfriend@gmail.com")
109
+ gmail.inbox.count(:to => "directlytome@gmail.com")
110
+
111
+ Combine flags and options:
112
+
113
+ gmail.inbox.count(:unread, :from => "myboss@gmail.com")
114
+
115
+ Browsing labeled emails is similar to work with inbox.
116
+
117
+ gmail.mailbox('Urgent').count
118
+
119
+ Getting messages works the same way as counting: Remember that every message in a
120
+ conversation/thread will come as a separate message.
121
+
122
+ gmail.inbox.emails(:unread, :before => Date.parse("2010-04-20"), :from => "myboss@gmail.com")
123
+
124
+ You can use also one of aliases:
125
+
126
+ gmail.inbox.find(...)
127
+ gmail.inbox.search(...)
128
+ gmail.inbox.mails(...)
129
+
130
+ Also you can manipulate each message using block style:
131
+
132
+ gmail.inbox.find(:unread) do |email|
133
+ email.read!
134
+ end
135
+
136
+ ### Working with emails!
137
+
138
+ Any news older than 4-20, mark as read and archive it:
139
+
140
+ gmail.inbox.find(:before => Date.parse("2010-04-20"), :from => "news@nbcnews.com") do |email|
141
+ email.read! # can also unread!, spam! or star!
142
+ email.archive!
143
+ end
144
+
145
+ Delete emails from X:
146
+
147
+ gmail.inbox.find(:from => "x-fiance@gmail.com").each do |email|
148
+ email.delete!
149
+ end
150
+
151
+ Save all attachments in the "Faxes" label to a local folder:
152
+
153
+ folder = "/where/ever"
154
+ gmail.mailbox("Faxes").emails do |email|
155
+ if !email.message.attachments.empty?
156
+ email.message.save_attachments_to(folder)
157
+ end
158
+ end
159
+
160
+ You can use also `#label` method instead of `#mailbox`:
161
+
162
+ gmail.label("Faxes").emails {|email| ... }
163
+
164
+ Save just the first attachment from the newest unread email (assuming pdf):
165
+
166
+ email = gmail.inbox.find(:unread).first
167
+ email.attachments[0].save_to_file("/path/to/location")
168
+
169
+ Add a label to a message:
170
+
171
+ email.label("Faxes")
172
+
173
+ Example above will raise error when you don't have the `Faxes` label. You can
174
+ avoid this using:
175
+
176
+ email.label!("Faxes") # The `Faxes` label will be automatically created now
177
+
178
+ You can also move message to a label/mailbox:
179
+
180
+ email.move_to("Faxes")
181
+ email.move_to!("NewLabel")
182
+
183
+ There is also few shortcuts to mark messages quickly:
184
+
185
+ email.read!
186
+ email.unread!
187
+ email.spam!
188
+ email.star!
189
+ email.unstar!
190
+
191
+ ### Managing labels
192
+
193
+ With Gmail gem you can also manage your labels. You can get list of defined
194
+ labels:
195
+
196
+ gmail.labels.all
197
+
198
+ Create new label:
199
+
200
+ gmail.labels.new("Uregent")
201
+ gmail.labels.add("AnotherOne")
202
+
203
+ Remove labels:
204
+
205
+ gmail.labels.delete("Uregent")
206
+
207
+ Or check if given label exists:
208
+
209
+ gmail.labels.exists?("Uregent") # => false
210
+ gmail.labels.exists?("AnotherOne") # => true
211
+
212
+ ### Composing and sending emails
213
+
214
+ Creating emails now uses the amazing [Mail](http://rubygems.org/gems/mail) rubygem.
215
+ See its [documentation here](http://github.com/mikel/mail). The Ruby Gmail will
216
+ automatically configure your Mail emails to be sent via your Gmail account's SMTP,
217
+ so they will be in your Gmail's "Sent" folder. Also, no need to specify the "From"
218
+ email either, because ruby-gmail will set it for you.
219
+
220
+ gmail.deliver do
221
+ to "email@example.com"
222
+ subject "Having fun in Puerto Rico!"
223
+ text_part do
224
+ body "Text of plaintext message."
225
+ end
226
+ html_part do
227
+ body "<p>Text of <em>html</em> message.</p>"
228
+ end
229
+ add_file "/path/to/some_image.jpg"
230
+ end
231
+
232
+ Or, generate the message first and send it later
233
+
234
+ email = gmail.generate_message do
235
+ to "email@example.com"
236
+ subject "Having fun in Puerto Rico!"
237
+ body "Spent the day on the road..."
238
+ end
239
+ email.deliver! # or: gmail.deliver(email)
240
+
241
+ ## Note on Patches/Pull Requests
242
+
243
+ * Fork the project.
244
+ * Make your feature addition or bug fix.
245
+ * Add tests for it. This is important so I don't break it in a
246
+ future version unintentionally.
247
+ * Commit, do not mess with rakefile, version, or history.
248
+ (if you want to have your own version, that is fine but bump version in a commit by itself I can ignore when I pull)
249
+ * Send me a pull request. Bonus points for topic branches.
250
+
251
+ ## Copyright
252
+
253
+ * Copyrignt (c) 2010 Kriss 'nu7hatch' Kowalik
254
+ * Copyright (c) 2009-2010 BehindLogic
255
+
256
+ See LICENSE for details.
257
+
data/Rakefile ADDED
@@ -0,0 +1,45 @@
1
+ # -*- ruby -*-
2
+ $:.unshift(File.expand_path('../lib', __FILE__))
3
+ require 'gmail/version'
4
+ require 'rspec/core/rake_task'
5
+ require 'rake/rdoctask'
6
+
7
+ RSpec::Core::RakeTask.new(:spec) do |t|
8
+ t.pattern = 'spec/**/*_spec.rb'
9
+ t.rspec_opts = %q[-c -b]
10
+ end
11
+
12
+ RSpec::Core::RakeTask.new(:rcov) do |t|
13
+ t.rcov = true
14
+ t.rspec_opts = %q[-c -b]
15
+ t.rcov_opts = %q[-T -x "spec"]
16
+ end
17
+
18
+ Rake::RDocTask.new do |rdoc|
19
+ rdoc.rdoc_dir = 'rdoc'
20
+ rdoc.title = "Gmail #{Gmail.version}"
21
+ rdoc.rdoc_files.include('README*')
22
+ rdoc.rdoc_files.include('lib/**/*.rb')
23
+ end
24
+
25
+ task :default => :spec
26
+
27
+ desc "Build current version as a rubygem"
28
+ task :build do
29
+ `gem build gmail-oauth.gemspec`
30
+ `mkdir -p pkg`
31
+ `mv gmail_oauth-*.gem pkg/`
32
+ end
33
+
34
+ desc "Relase current version to rubygems.org"
35
+ task :release => :build do
36
+ `git tag -am "Version bump to #{Gmail.version}" v#{Gmail.version}`
37
+ `git push origin master`
38
+ `git push origin master --tags`
39
+ `gem push pkg/gmail_oauth-#{Gmail.version}.gem`
40
+ end
41
+
42
+ desc "Perform installation via rubygems"
43
+ task :install => :build do
44
+ `gem install pkg/gmail_oauth-#{Gmail.version}.gem`
45
+ end
data/TODO.md ADDED
@@ -0,0 +1,3 @@
1
+ # TODO
2
+
3
+ * Specs
@@ -0,0 +1,236 @@
1
+ module Gmail
2
+ class Client
3
+ # Raised when connection with GMail IMAP service couldn't be established.
4
+ class ConnectionError < SocketError; end
5
+ # Raised when given username or password are invalid.
6
+ class AuthorizationError < Net::IMAP::NoResponseError; end
7
+ # Raised when delivered email is invalid.
8
+ class DeliveryError < ArgumentError; end
9
+
10
+ # GMail IMAP defaults
11
+ GMAIL_IMAP_HOST = 'imap.gmail.com'
12
+ GMAIL_IMAP_PORT = 993
13
+
14
+ # GMail SMTP defaults
15
+ GMAIL_SMTP_HOST = "smtp.gmail.com"
16
+ GMAIL_SMTP_PORT = 587
17
+
18
+ attr_reader :email
19
+ attr_reader :token
20
+ attr_reader :secret
21
+ attr_reader :options
22
+
23
+ def initialize(email, token, secret, consumer_key, consumer_secret, options={})
24
+ defaults = {}
25
+ @email = email
26
+ @username = email
27
+ @token = token
28
+ @secret = secret
29
+ @consumer_key = consumer_key
30
+ @consumer_secret = consumer_secret
31
+ @options = defaults.merge(options)
32
+ end
33
+
34
+ # Connect to gmail service.
35
+ def connect(raise_errors=false)
36
+ @imap = Net::IMAP.new(GMAIL_IMAP_HOST, GMAIL_IMAP_PORT, true, nil, false)
37
+ rescue SocketError
38
+ raise_errors and raise ConnectionError, "Couldn't establish connection with GMail IMAP service"
39
+ end
40
+
41
+ # This version of connect will raise error on failure...
42
+ def connect!
43
+ connect(true)
44
+ end
45
+
46
+ # Return current connection. Log in automaticaly to specified account if
47
+ # it is necessary.
48
+ def connection
49
+ login and at_exit { logout } unless logged_in?
50
+ @imap
51
+ end
52
+ alias :conn :connection
53
+
54
+ # Login to specified account.
55
+ def login(raise_errors=false)
56
+ @imap and @logged_in = (login = @imap.authenticate('XOAUTH', email,
57
+ :consumer_key => consumer_key,
58
+ :consumer_secret => consumer_secret,
59
+ :token => token,
60
+ :token_secret => secret
61
+ )) && login.name == 'OK'
62
+ rescue Net::IMAP::NoResponseError
63
+ raise_errors and raise AuthorizationError, "Couldn't login to given GMail account"
64
+ end
65
+ alias :sign_in :login
66
+
67
+ # This version of login will raise error on failure...
68
+ def login!
69
+ login(true)
70
+ end
71
+ alias :sign_in! :login!
72
+
73
+ # Returns +true+ when you are logged in to specified account.
74
+ def logged_in?
75
+ !!@logged_in
76
+ end
77
+ alias :signed_in? :logged_in?
78
+
79
+ # Logout from GMail service.
80
+ def logout
81
+ @imap && logged_in? and @imap.logout
82
+ ensure
83
+ @logged_in = false
84
+ end
85
+ alias :sign_out :logout
86
+
87
+ # Return labels object, which helps you with managing your GMail labels.
88
+ # See <tt>Gmail::Labels</tt> for details.
89
+ def labels
90
+ @labels ||= Labels.new(conn)
91
+ end
92
+
93
+ # Compose new e-mail.
94
+ #
95
+ # ==== Examples
96
+ #
97
+ # mail = gmail.compose
98
+ # mail.from "test@gmail.org"
99
+ # mail.to "friend@gmail.com"
100
+ #
101
+ # ... or block style:
102
+ #
103
+ # mail = gmail.compose do
104
+ # from "test@gmail.org"
105
+ # to "friend@gmail.com"
106
+ # subject "Hello!"
107
+ # body "Hello my friend! long time..."
108
+ # end
109
+ #
110
+ # Now you can deliver your mail:
111
+ #
112
+ # gmail.deliver(mail)
113
+ def compose(mail=nil, &block)
114
+ if block_given?
115
+ mail = Mail.new(&block)
116
+ elsif !mail
117
+ mail = Mail.new
118
+ end
119
+ mail.delivery_method(*smtp_settings)
120
+ mail.from = @email unless mail.from
121
+ mail
122
+ end
123
+ alias :message :compose
124
+
125
+ # Compose (optionaly) and send given email.
126
+ #
127
+ # ==== Examples
128
+ #
129
+ # gmail.deliver do
130
+ # to "friend@gmail.com"
131
+ # subject "Hello friend!"
132
+ # body "Hi! How are you?"
133
+ # end
134
+ #
135
+ # ... or with already created message:
136
+ #
137
+ # mail = Mail.new { ... }
138
+ # gmail.deliver(mail)
139
+ #
140
+ # mail = gmail.compose { ... }
141
+ # gmail.deliver(mail)
142
+ def deliver(mail=nil, raise_errors=false, &block)
143
+ mail = compose(mail, &block) if block_given?
144
+ mail.deliver!
145
+ rescue Object => ex
146
+ raise_errors and raise DeliveryError, "Couldn't deliver email: #{ex.to_s}"
147
+ end
148
+
149
+ # This version of deliver will raise error on failure...
150
+ def deliver!(mail=nil, &block)
151
+ deliver(mail, true, &block)
152
+ end
153
+
154
+ # Do something with given mailbox or within it context.
155
+ #
156
+ # ==== Examples
157
+ #
158
+ # mailbox = gmail.mailbox("INBOX")
159
+ # mailbox.emails(:all)
160
+ # mailbox.count(:unread, :before => Time.now-(20*24*3600))
161
+ #
162
+ # ... or block style:
163
+ #
164
+ # gmail.label("Work") do |mailbox|
165
+ # mailbox.emails(:unread)
166
+ # mailbox.count(:all)
167
+ # ...
168
+ # end
169
+ def mailbox(name, &block)
170
+ name = Net::IMAP.encode_utf7(name.to_s)
171
+ mailbox = (mailboxes[name] ||= Mailbox.new(self, name))
172
+ switch_to_mailbox(name) if @current_mailbox != name
173
+ if block_given?
174
+ mailbox_stack << @current_mailbox
175
+ result = block.arity == 1 ? block.call(mailbox) : block.call
176
+ mailbox_stack.pop
177
+ switch_to_mailbox(mailbox_stack.last)
178
+ return result
179
+ end
180
+ mailbox
181
+ end
182
+ alias :in_mailbox :mailbox
183
+ alias :in_label :mailbox
184
+ alias :label :mailbox
185
+
186
+ # Alias for <tt>mailbox("INBOX")</tt>. See <tt>Gmail::Client#mailbox</tt>
187
+ # for details.
188
+ def inbox
189
+ mailbox("INBOX")
190
+ end
191
+
192
+ def mailboxes
193
+ @mailboxes ||= {}
194
+ end
195
+
196
+ def inspect
197
+ "#<Gmail::Client#{'0x%04x' % (object_id << 1)} (#{@email}) #{'dis' if !logged_in?}connected>"
198
+ end
199
+
200
+ #def fill_username(username)
201
+ # username =~ /@/ ? username : "#{username}@gmail.com"
202
+ #end
203
+
204
+ def mail_domain
205
+ @email.split('@')[0]
206
+ end
207
+
208
+ private
209
+
210
+ def switch_to_mailbox(mailbox)
211
+ conn.select(mailbox) if mailbox
212
+ @current_mailbox = mailbox
213
+ end
214
+
215
+ def mailbox_stack
216
+ @mailbox_stack ||= []
217
+ end
218
+
219
+ def smtp_settings
220
+ [:smtp, {
221
+ :address => GMAIL_SMTP_HOST,
222
+ :port => GMAIL_SMTP_PORT,
223
+ :domain => mail_domain,
224
+ :user_name => username,
225
+ :password => {
226
+ :consumer_key => 'anonymous',
227
+ :consumer_secret => 'anonymous',
228
+ :token => '4/nM2QAaunKUINb4RrXPC55F-mix_k',
229
+ :token_secret => '41r18IyXjIvuyabS/NDyW6+m'
230
+ }
231
+ :authentication => 'xoauth',
232
+ :enable_starttls_auto => true
233
+ }]
234
+ end
235
+ end # Client
236
+ end # Gmail
@@ -0,0 +1,48 @@
1
+ module Gmail
2
+ class Labels
3
+ include Enumerable
4
+ attr_reader :connection
5
+ alias :conn :connection
6
+
7
+ def initialize(connection)
8
+ @connection = connection
9
+ end
10
+
11
+ # Get list of all defined labels.
12
+ def all
13
+ (conn.list("", "%")+conn.list("[Gmail]/", "%")).inject([]) do |labels,label|
14
+ label[:name].each_line {|l| labels << Net::IMAP.decode_utf7(l) }
15
+ labels
16
+ end
17
+ end
18
+ alias :list :all
19
+ alias :to_a :all
20
+
21
+ def each(*args, &block)
22
+ all.each(*args, &block)
23
+ end
24
+
25
+ # Returns +true+ when given label defined.
26
+ def exists?(label)
27
+ all.include?(Net::IMAP.encode_utf7(label))
28
+ end
29
+ alias :exist? :exists?
30
+
31
+ # Creates given label in your account.
32
+ def create(label)
33
+ !!conn.create(Net::IMAP.encode_utf7(label)) rescue false
34
+ end
35
+ alias :new :create
36
+ alias :add :create
37
+
38
+ # Deletes given label from your account.
39
+ def delete(label)
40
+ !!conn.delete(Net::IMAP.encode_utf7(label)) rescue false
41
+ end
42
+ alias :remove :delete
43
+
44
+ def inspect
45
+ "#<Gmail::Labels#{'0x%04x' % (object_id << 1)}>"
46
+ end
47
+ end # Labels
48
+ end # Gmail
@@ -0,0 +1,115 @@
1
+ module Gmail
2
+ class Mailbox
3
+ MAILBOX_ALIASES = {
4
+ :all => ['ALL'],
5
+ :seen => ['SEEN'],
6
+ :unseen => ['UNSEEN'],
7
+ :read => ['SEEN'],
8
+ :unread => ['UNSEEN'],
9
+ :flagged => ['FLAGGED'],
10
+ :unflagged => ['UNFLAGGED'],
11
+ :starred => ['FLAGGED'],
12
+ :unstarred => ['UNFLAGGED'],
13
+ :deleted => ['DELETED'],
14
+ :undeleted => ['UNDELETED'],
15
+ :draft => ['DRAFT'],
16
+ :undrafted => ['UNDRAFT']
17
+ }
18
+
19
+ attr_reader :name
20
+ attr_reader :external_name
21
+
22
+ def initialize(gmail, name="INBOX")
23
+ @name = name
24
+ @external_name = Net::IMAP.decode_utf7(name)
25
+ @gmail = gmail
26
+ end
27
+
28
+ # Returns list of emails which meets given criteria.
29
+ #
30
+ # ==== Examples
31
+ #
32
+ # gmail.inbox.emails(:all)
33
+ # gmail.inbox.emails(:unread, :from => "friend@gmail.com")
34
+ # gmail.inbox.emails(:all, :after => Time.now-(20*24*3600))
35
+ # gmail.mailbox("Test").emails(:read)
36
+ #
37
+ # gmail.mailbox("Test") do |box|
38
+ # box.emails(:read)
39
+ # box.emails(:unread) do |email|
40
+ # ... do something with each email...
41
+ # end
42
+ # end
43
+ def emails(*args, &block)
44
+ args << :all if args.size == 0
45
+
46
+ if args.first.is_a?(Symbol)
47
+ search = MAILBOX_ALIASES[args.shift].dup
48
+ opts = args.first.is_a?(Hash) ? args.first : {}
49
+
50
+ opts[:after] and search.concat ['SINCE', opts[:after].to_imap_date]
51
+ opts[:before] and search.concat ['BEFORE', opts[:before].to_imap_date]
52
+ opts[:on] and search.concat ['ON', opts[:on].to_imap_date]
53
+ opts[:from] and search.concat ['FROM', opts[:from]]
54
+ opts[:to] and search.concat ['TO', opts[:to]]
55
+ opts[:subject] and search.concat ['SUBJECT', opts[:subject]]
56
+ opts[:label] and search.concat ['LABEL', opts[:label]]
57
+ opts[:attachment] and search.concat ['HAS', 'attachment']
58
+ opts[:search] and search.concat [opts[:search]]
59
+
60
+ @gmail.mailbox(name) do
61
+ @gmail.conn.uid_search(search).collect do |uid|
62
+ message = (messages[uid] ||= Message.new(self, uid))
63
+ block.call(message) if block_given?
64
+ message
65
+ end
66
+ end
67
+ elsif args.first.is_a?(Hash)
68
+ emails(:all, args.first)
69
+ else
70
+ raise ArgumentError, "Invalid search criteria"
71
+ end
72
+ end
73
+ alias :mails :emails
74
+ alias :search :emails
75
+ alias :find :emails
76
+ alias :filter :emails
77
+
78
+ # This is a convenience method that really probably shouldn't need to exist,
79
+ # but it does make code more readable, if seriously all you want is the count
80
+ # of messages.
81
+ #
82
+ # ==== Examples
83
+ #
84
+ # gmail.inbox.count(:all)
85
+ # gmail.inbox.count(:unread, :from => "friend@gmail.com")
86
+ # gmail.mailbox("Test").count(:all, :after => Time.now-(20*24*3600))
87
+ def count(*args)
88
+ emails(*args).size
89
+ end
90
+
91
+ # This permanently removes messages which are marked as deleted
92
+ def expunge
93
+ @gmail.mailbox(name) { @gmail.conn.expunge }
94
+ end
95
+
96
+ # Cached messages.
97
+ def messages
98
+ @messages ||= {}
99
+ end
100
+
101
+ def inspect
102
+ "#<Gmail::Mailbox#{'0x%04x' % (object_id << 1)} name=#{external_name}>"
103
+ end
104
+
105
+ def to_s
106
+ name
107
+ end
108
+
109
+ MAILBOX_ALIASES.each_key { |mailbox|
110
+ define_method(mailbox) do |*args, &block|
111
+ emails(mailbox, *args, &block)
112
+ end
113
+ }
114
+ end # Message
115
+ end # Gmail
@@ -0,0 +1,164 @@
1
+ require 'mime/message'
2
+
3
+ module Gmail
4
+ class Message
5
+ # Raised when given label doesn't exists.
6
+ class NoLabelError < Exception; end
7
+
8
+ attr_reader :uid
9
+
10
+ def initialize(mailbox, uid)
11
+ @uid = uid
12
+ @mailbox = mailbox
13
+ @gmail = mailbox.instance_variable_get("@gmail") if mailbox
14
+ end
15
+
16
+ def uid
17
+ @uid ||= @gmail.conn.uid_search(['HEADER', 'Message-ID', message_id])[0]
18
+ end
19
+
20
+ # Mark message with given flag.
21
+ def flag(name)
22
+ !!@gmail.mailbox(@mailbox.name) { @gmail.conn.uid_store(uid, "+FLAGS", [name]) }
23
+ end
24
+
25
+ # Unmark message.
26
+ def unflag(name)
27
+ !!@gmail.mailbox(@mailbox.name) { @gmail.conn.uid_store(uid, "-FLAGS", [name]) }
28
+ end
29
+
30
+ # Do commonly used operations on message.
31
+ def mark(flag)
32
+ case flag
33
+ when :read then read!
34
+ when :unread then unread!
35
+ when :deleted then delete!
36
+ when :spam then spam!
37
+ else
38
+ flag(flag)
39
+ end
40
+ end
41
+
42
+ # Mark this message as a spam.
43
+ def spam!
44
+ move_to('[Gmail]/Spam')
45
+ end
46
+
47
+ # Mark as read.
48
+ def read!
49
+ flag(:Seen)
50
+ end
51
+
52
+ # Mark as unread.
53
+ def unread!
54
+ unflag(:Seen)
55
+ end
56
+
57
+ # Mark message with star.
58
+ def star!
59
+ flag('[Gmail]/Starred')
60
+ end
61
+
62
+ # Remove message from list of starred.
63
+ def unstar!
64
+ unflag('[Gmail]/Starred')
65
+ end
66
+
67
+ # Move to trash / bin.
68
+ def delete!
69
+ @mailbox.messages.delete(uid)
70
+ flag(:deleted)
71
+
72
+ # For some, it's called "Trash", for others, it's called "Bin". Support both.
73
+ trash = @gmail.labels.exist?('[Gmail]/Bin') ? '[Gmail]/Bin' : '[Gmail]/Trash'
74
+ move_to(trash) unless %w[[Gmail]/Spam [Gmail]/Bin [Gmail]/Trash].include?(@mailbox.name)
75
+ end
76
+
77
+ # Archive this message.
78
+ def archive!
79
+ move_to('[Gmail]/All Mail')
80
+ end
81
+
82
+ # Move to given box and delete from others.
83
+ def move_to(name, from=nil)
84
+ label(name, from)
85
+ delete! if !%w[[Gmail]/Bin [Gmail]/Trash].include?(name)
86
+ end
87
+ alias :move :move_to
88
+
89
+ # Move message to given and delete from others. When given mailbox doesn't
90
+ # exist then it will be automaticaly created.
91
+ def move_to!(name, from=nil)
92
+ label!(name, from) && delete!
93
+ end
94
+ alias :move! :move_to!
95
+
96
+ # Mark this message with given label. When given label doesn't exist then
97
+ # it will raise <tt>NoLabelError</tt>.
98
+ #
99
+ # See also <tt>Gmail::Message#label!</tt>.
100
+ def label(name, from=nil)
101
+ @gmail.mailbox(Net::IMAP.encode_utf7(from || @mailbox.external_name)) { @gmail.conn.uid_copy(uid, Net::IMAP.encode_utf7(name)) }
102
+ rescue Net::IMAP::NoResponseError
103
+ raise NoLabelError, "Label '#{name}' doesn't exist!"
104
+ end
105
+
106
+ # Mark this message with given label. When given label doesn't exist then
107
+ # it will be automaticaly created.
108
+ #
109
+ # See also <tt>Gmail::Message#label</tt>.
110
+ def label!(name, from=nil)
111
+ label(name, from)
112
+ rescue NoLabelError
113
+ @gmail.labels.add(Net::IMAP.encode_utf7(name))
114
+ label(name, from)
115
+ end
116
+ alias :add_label :label!
117
+ alias :add_label! :label!
118
+
119
+ # Remove given label from this message.
120
+ def remove_label!(name)
121
+ move_to('[Gmail]/All Mail', name)
122
+ end
123
+ alias :delete_label! :remove_label!
124
+
125
+ def inspect
126
+ "#<Gmail::Message#{'0x%04x' % (object_id << 1)} mailbox=#{@mailbox.external_name}#{' uid='+@uid.to_s if @uid}#{' message_id='+@message_id.to_s if @message_id}>"
127
+ end
128
+
129
+ def method_missing(meth, *args, &block)
130
+ # Delegate rest directly to the message.
131
+ if envelope.respond_to?(meth)
132
+ envelope.send(meth, *args, &block)
133
+ elsif message.respond_to?(meth)
134
+ message.send(meth, *args, &block)
135
+ else
136
+ super(meth, *args, &block)
137
+ end
138
+ end
139
+
140
+ def respond_to?(meth, *args, &block)
141
+ if envelope.respond_to?(meth)
142
+ return true
143
+ elsif message.respond_to?(meth)
144
+ return true
145
+ else
146
+ super(meth, *args, &block)
147
+ end
148
+ end
149
+
150
+ def envelope
151
+ @envelope ||= @gmail.mailbox(@mailbox.name) {
152
+ @gmail.conn.uid_fetch(uid, "ENVELOPE")[0].attr["ENVELOPE"]
153
+ }
154
+ end
155
+
156
+ private
157
+
158
+ def message
159
+ @message ||= Mail.new(@gmail.mailbox(@mailbox.name) {
160
+ @gmail.conn.uid_fetch(uid, "RFC822")[0].attr["RFC822"] # RFC822
161
+ })
162
+ end
163
+ end # Message
164
+ end # Gmail
@@ -0,0 +1,12 @@
1
+ module Gmail
2
+ class Version #:nodoc:
3
+ MAJOR = 0
4
+ MINOR = 1
5
+ PATCH = 1
6
+ STRING = [MAJOR, MINOR, PATCH].join('.')
7
+ end # Version
8
+
9
+ def self.version # :nodoc:
10
+ Version::STRING
11
+ end
12
+ end # Gmail
data/lib/gmail.rb ADDED
@@ -0,0 +1,48 @@
1
+ require 'net/imap'
2
+ require 'net/smtp'
3
+ require 'mail'
4
+ require 'date'
5
+ require 'time'
6
+ require 'gmail_xoauth'
7
+
8
+ if RUBY_VERSION < "1.8.7"
9
+ require "smtp_tls"
10
+ end
11
+
12
+ class Object
13
+ def to_imap_date
14
+ Date.parse(to_s).strftime("%d-%B-%Y")
15
+ end
16
+ end
17
+
18
+ module Gmail
19
+ autoload :Version, "gmail/version"
20
+ autoload :Client, "gmail/client"
21
+ autoload :Labels, "gmail/labels"
22
+ autoload :Mailbox, "gmail/mailbox"
23
+ autoload :Message, "gmail/message"
24
+
25
+ class << self
26
+ def new(email, token, secret, consumer_key, consumer_secret, options={}, &block)
27
+ client = Client.new(email, token, secret, consumer_key, consumer_secret, options)
28
+ client.connect and client.login
29
+ if block_given?
30
+ yield client
31
+ client.logout
32
+ end
33
+ client
34
+ end
35
+ alias :connect :new
36
+
37
+ def new!(email, token, secret, consumer_key, consumer_secret, options={}, &block)
38
+ client = Client.new(email, token, secret, consumer_key, consumer_secret, options)
39
+ client.connect! and client.login!
40
+ if block_given?
41
+ yield client
42
+ client.logout
43
+ end
44
+ client
45
+ end
46
+ alias :connect! :new!
47
+ end # << self
48
+ end # Gmail
metadata ADDED
@@ -0,0 +1,151 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: gmail_oauth
3
+ version: !ruby/object:Gem::Version
4
+ prerelease: false
5
+ segments:
6
+ - 0
7
+ - 1
8
+ - 1
9
+ version: 0.1.1
10
+ platform: ruby
11
+ authors:
12
+ - BehindLogic
13
+ - Chris Kowalik
14
+ - Stefano Bernardi
15
+ autorequire:
16
+ bindir: bin
17
+ cert_chain: []
18
+
19
+ date: 2010-12-14 00:00:00 +01:00
20
+ default_executable:
21
+ dependencies:
22
+ - !ruby/object:Gem::Dependency
23
+ name: mime
24
+ prerelease: false
25
+ requirement: &id001 !ruby/object:Gem::Requirement
26
+ none: false
27
+ requirements:
28
+ - - ">="
29
+ - !ruby/object:Gem::Version
30
+ segments:
31
+ - 0
32
+ - 1
33
+ version: "0.1"
34
+ type: :runtime
35
+ version_requirements: *id001
36
+ - !ruby/object:Gem::Dependency
37
+ name: mail
38
+ prerelease: false
39
+ requirement: &id002 !ruby/object:Gem::Requirement
40
+ none: false
41
+ requirements:
42
+ - - ">="
43
+ - !ruby/object:Gem::Version
44
+ segments:
45
+ - 2
46
+ - 2
47
+ - 1
48
+ version: 2.2.1
49
+ type: :runtime
50
+ version_requirements: *id002
51
+ - !ruby/object:Gem::Dependency
52
+ name: gmail_xoauth
53
+ prerelease: false
54
+ requirement: &id003 !ruby/object:Gem::Requirement
55
+ none: false
56
+ requirements:
57
+ - - ">="
58
+ - !ruby/object:Gem::Version
59
+ segments:
60
+ - 0
61
+ - 3
62
+ version: "0.3"
63
+ type: :runtime
64
+ version_requirements: *id003
65
+ - !ruby/object:Gem::Dependency
66
+ name: rspec
67
+ prerelease: false
68
+ requirement: &id004 !ruby/object:Gem::Requirement
69
+ none: false
70
+ requirements:
71
+ - - ~>
72
+ - !ruby/object:Gem::Version
73
+ segments:
74
+ - 2
75
+ - 0
76
+ version: "2.0"
77
+ type: :development
78
+ version_requirements: *id004
79
+ - !ruby/object:Gem::Dependency
80
+ name: mocha
81
+ prerelease: false
82
+ requirement: &id005 !ruby/object:Gem::Requirement
83
+ none: false
84
+ requirements:
85
+ - - ">="
86
+ - !ruby/object:Gem::Version
87
+ segments:
88
+ - 0
89
+ - 9
90
+ version: "0.9"
91
+ type: :development
92
+ version_requirements: *id005
93
+ description: A Rubyesque interface to Gmail with Oauth, with all the tools you will need. Search, read and send multipart emails; archive, mark as read/unread, delete emails; and manage labels.
94
+ email:
95
+ - hello@stefanobernardi.com
96
+ executables: []
97
+
98
+ extensions: []
99
+
100
+ extra_rdoc_files:
101
+ - LICENSE
102
+ - README.md
103
+ - CHANGELOG.md
104
+ - TODO.md
105
+ files:
106
+ - .gitignore
107
+ - CHANGELOG.md
108
+ - LICENSE
109
+ - README.md
110
+ - Rakefile
111
+ - TODO.md
112
+ - lib/gmail.rb
113
+ - lib/gmail/client.rb
114
+ - lib/gmail/labels.rb
115
+ - lib/gmail/mailbox.rb
116
+ - lib/gmail/message.rb
117
+ - lib/gmail/version.rb
118
+ has_rdoc: true
119
+ homepage: http://github.com/stefanobernardi/gmail_oauth
120
+ licenses: []
121
+
122
+ post_install_message:
123
+ rdoc_options: []
124
+
125
+ require_paths:
126
+ - lib
127
+ required_ruby_version: !ruby/object:Gem::Requirement
128
+ none: false
129
+ requirements:
130
+ - - ">="
131
+ - !ruby/object:Gem::Version
132
+ segments:
133
+ - 0
134
+ version: "0"
135
+ required_rubygems_version: !ruby/object:Gem::Requirement
136
+ none: false
137
+ requirements:
138
+ - - ">="
139
+ - !ruby/object:Gem::Version
140
+ segments:
141
+ - 0
142
+ version: "0"
143
+ requirements: []
144
+
145
+ rubyforge_project:
146
+ rubygems_version: 1.3.7
147
+ signing_key:
148
+ specification_version: 3
149
+ summary: A Rubyesque interface to Gmail with Oauth, with all the tools you will need.
150
+ test_files: []
151
+