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 +25 -0
- data/CHANGELOG.md +5 -0
- data/LICENSE +21 -0
- data/README.md +257 -0
- data/Rakefile +45 -0
- data/TODO.md +3 -0
- data/lib/gmail/client.rb +236 -0
- data/lib/gmail/labels.rb +48 -0
- data/lib/gmail/mailbox.rb +115 -0
- data/lib/gmail/message.rb +164 -0
- data/lib/gmail/version.rb +12 -0
- data/lib/gmail.rb +48 -0
- metadata +151 -0
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
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
data/lib/gmail/client.rb
ADDED
@@ -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
|
data/lib/gmail/labels.rb
ADDED
@@ -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
|
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
|
+
|