pauldix-ruby-gmail 0.2.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,23 @@
1
+ # -*- ruby -*-
2
+
3
+ require 'autotest/restart'
4
+
5
+ # Autotest.add_hook :initialize do |at|
6
+ # at.extra_files << "../some/external/dependency.rb"
7
+ #
8
+ # at.libs << ":../some/external"
9
+ #
10
+ # at.add_exception 'vendor'
11
+ #
12
+ # at.add_mapping(/dependency.rb/) do |f, _|
13
+ # at.files_matching(/test_.*rb$/)
14
+ # end
15
+ #
16
+ # %w(TestA TestB).each do |klass|
17
+ # at.extra_class_map[klass] = "test/test_misc.rb"
18
+ # end
19
+ # end
20
+
21
+ # Autotest.add_hook :run_command do |at|
22
+ # system "rake build"
23
+ # end
@@ -0,0 +1 @@
1
+ pkg
@@ -0,0 +1,75 @@
1
+ === 0.1.1 / 2010-05-11
2
+
3
+ * 1 minor fix
4
+
5
+ * Added explicit tmail dependency in gemspec
6
+ * Added better README tutorial content
7
+
8
+ === 0.0.9 / 2010-04-17
9
+
10
+ * 1 bugfix
11
+
12
+ * Fixed content-transfer-encoding when sending email
13
+
14
+ === 0.0.8 / 2009-12-23
15
+
16
+ * 1 bugfix
17
+
18
+ * Fixed attaching a file to an empty message
19
+
20
+ === 0.0.7 / 2009-12-23
21
+
22
+ * 1 bugfix
23
+
24
+ * Improved multipart message parsing reliability
25
+
26
+ === 0.0.6 / 2009-12-21
27
+
28
+ * 1 bugfix
29
+
30
+ * Fixed multipart parsing for when the boundary is marked in quotes.
31
+
32
+ === 0.0.5 / 2009-12-16
33
+
34
+ * 1 bugfix
35
+
36
+ * Fixed IMAP initializer to work with Ruby 1.9's net/imap
37
+
38
+ * 4 minor enhancements
39
+
40
+ * Better logout depending on the IMAP connection itself
41
+ * Added MIME::Message#text and MIME::Message#html for easier access to an email body
42
+ * Improved the MIME-parsing API slightly
43
+ * Added some tests
44
+
45
+ === 0.0.4 / 2009-11-30
46
+
47
+ * 4 minor enhancement
48
+
49
+ * Added label creation (thanks to Justin Perkins / http://github.com/justinperkins)
50
+ * Made the gem login automatically when first needed
51
+ * Added an optional block on the Gmail.new object that will login and logout for you
52
+ * Added several search options (thanks to Mikkel Malmberg / http://github.com/mikker)
53
+
54
+ === 0.0.3 / 2009-11-19
55
+
56
+ * 1 bugfix
57
+
58
+ * Fixed MIME::Message#content= for messages without an encoding
59
+
60
+ * 1 minor enhancement
61
+
62
+ * Added Gmail#new_message
63
+
64
+ === 0.0.2 / 2009-11-18
65
+
66
+ * 1 minor enhancement
67
+
68
+ * Made all of the examples in the README possible
69
+
70
+ === 0.0.1 / 2009-11-18
71
+
72
+ * 1 major enhancement
73
+
74
+ * Birthday!
75
+
@@ -0,0 +1,14 @@
1
+ .autotest
2
+ History.txt
3
+ lib/gmail/mailbox.rb
4
+ lib/gmail/message.rb
5
+ lib/gmail.rb
6
+ lib/ietf/rfc2045.rb
7
+ lib/ietf/rfc822.rb
8
+ lib/mime/entity.rb
9
+ lib/mime/entity_tmail.rb
10
+ lib/mime/message.rb
11
+ lib/smtp_tls.rb
12
+ Manifest.txt
13
+ Rakefile
14
+ README.markdown
@@ -0,0 +1,172 @@
1
+ # ruby-gmail
2
+
3
+ * Homepage: [http://dcparker.github.com/ruby-gmail/](http://dcparker.github.com/ruby-gmail/)
4
+ * Code: [http://github.com/dcparker/ruby-gmail](http://github.com/dcparker/ruby-gmail)
5
+ * Gem: [http://gemcutter.org/gems/ruby-gmail](http://gemcutter.org/gems/ruby-gmail)
6
+
7
+ ## Author(s)
8
+
9
+ * Daniel Parker of BehindLogic.com
10
+
11
+ Extra thanks for specific feature contributions from:
12
+
13
+ * [Justin Perkins](http://github.com/justinperkins)
14
+ * [Mikkel Malmberg](http://github.com/mikker)
15
+ * [Julien Blanchard](http://github.com/julienXX)
16
+ * [Federico Galassi](http://github.com/fgalassi)
17
+
18
+ ## Description
19
+
20
+ A Rubyesque interface to Gmail, with all the tools you'll need. Search, read and send multipart emails; archive, mark as read/unread, delete emails; and manage labels.
21
+
22
+ ## Features
23
+
24
+ * Search emails
25
+ * Read emails (handles attachments)
26
+ * Emails: Label, archive, delete, mark as read/unread/spam
27
+ * Create and delete labels
28
+ * Create and send multipart email messages in plaintext and/or html, with inline images and attachments
29
+ * Utilizes Gmail's IMAP & SMTP, MIME-type detection and parses and generates MIME properly.
30
+
31
+ ## Problems:
32
+
33
+ * May not correctly read malformed MIME messages. This could possibly be corrected by having IMAP parse the MIME structure.
34
+ * Cannot grab the plain or html message without also grabbing attachments. It might be nice to lazy-[down]load attachments.
35
+
36
+ ## Example Code:
37
+
38
+ ### 1) Require gmail
39
+
40
+ require 'gmail'
41
+
42
+ ### 2) Start an authenticated gmail session
43
+
44
+ # If you pass a block, the session will be passed into the block,
45
+ # and the session will be logged out after the block is executed.
46
+ gmail = Gmail.new(username, password)
47
+ # ...do things...
48
+ gmail.logout
49
+
50
+ Gmail.new(username, password) do |gmail|
51
+ # ...do things...
52
+ end
53
+
54
+ ### 3) Count and gather emails!
55
+
56
+ # Get counts for messages in the inbox
57
+ gmail.inbox.count
58
+ gmail.inbox.count(:unread)
59
+ gmail.inbox.count(:read)
60
+
61
+ # Count with some criteria
62
+ gmail.inbox.count(:after => Date.parse("2010-02-20"), :before => Date.parse("2010-03-20"))
63
+ gmail.inbox.count(:on => Date.parse("2010-04-15"))
64
+ gmail.inbox.count(:from => "myfriend@gmail.com")
65
+ gmail.inbox.count(:to => "directlytome@gmail.com")
66
+
67
+ # Combine flags and options
68
+ gmail.inbox.count(:unread, :from => "myboss@gmail.com")
69
+
70
+ # Labels work the same way as inbox
71
+ gmail.mailbox('Urgent').count
72
+
73
+ # Getting messages works the same way as counting: optional flag, and optional arguments
74
+ # Remember that every message in a conversation/thread will come as a separate message.
75
+ gmail.inbox.emails(:unread, :before => Date.parse("2010-04-20"), :from => "myboss@gmail.com")
76
+
77
+ ### 4) Work with emails!
78
+
79
+ # any news older than 4-20, mark as read and archive it...
80
+ gmail.inbox.emails(:before => Date.parse("2010-04-20"), :from => "news@nbcnews.com").each do |email|
81
+ email.mark(:read) # can also mark :unread or :spam
82
+ email.archive!
83
+ end
84
+
85
+ # delete emails from X...
86
+ gmail.inbox.emails(:from => "x-fiancé@gmail.com").each do |email|
87
+ email.delete!
88
+ end
89
+
90
+ # Save all attachments in the "Faxes" label to a folder
91
+ folder = "/where/ever"
92
+ gmail.mailbox("Faxes").emails.each do |email|
93
+ if !email.message.attachments.empty?
94
+ email.message.save_attachments_to(folder)
95
+ end
96
+ end
97
+
98
+ # Save just the first attachment from the newest unread email (assuming pdf)
99
+ # For #save_to_file:
100
+ # + provide a path - save to attachment filename in path
101
+ # + provide a filename - save to file specified
102
+ # + provide no arguments - save to attachment filename in current directory
103
+ email = gmail.inbox.emails(:unread).first
104
+ email.attachments[0].save_to_file("/path/to/location")
105
+
106
+ # Add a label to a message
107
+ email.label("Faxes")
108
+
109
+ # Or "move" the message to a label
110
+ email.move_to("Faxes")
111
+
112
+ ### 5) Create new emails!
113
+
114
+ Creating emails now uses the amazing [Mail](http://rubygems.org/gems/mail) rubygem. See its [documentation here](http://github.com/mikel/mail). Ruby-gmail will automatically configure your Mail emails to be sent via your Gmail account's SMTP, so they will be in your Gmail's "Sent" folder. Also, no need to specify the "From" email either, because ruby-gmail will set it for you.
115
+
116
+ gmail.deliver do
117
+ to "email@example.com"
118
+ subject "Having fun in Puerto Rico!"
119
+ text_part do
120
+ body "Text of plaintext message."
121
+ end
122
+ html_part do
123
+ body "<p>Text of <em>html</em> message.</p>"
124
+ end
125
+ add_file "/path/to/some_image.jpg"
126
+ end
127
+ # Or, generate the message first and send it later
128
+ email = gmail.generate_message do
129
+ to "email@example.com"
130
+ subject "Having fun in Puerto Rico!"
131
+ body "Spent the day on the road..."
132
+ end
133
+ email.deliver!
134
+ # Or...
135
+ gmail.deliver(email)
136
+
137
+ ## Requirements
138
+
139
+ * ruby
140
+ * net/smtp
141
+ * net/imap
142
+ * tmail
143
+ * shared-mime-info rubygem (for MIME-detection when attaching files)
144
+
145
+ ## Install
146
+
147
+ gem install ruby-gmail
148
+
149
+ ## License
150
+
151
+ (The MIT License)
152
+
153
+ Copyright (c) 2009 BehindLogic
154
+
155
+ Permission is hereby granted, free of charge, to any person obtaining
156
+ a copy of this software and associated documentation files (the
157
+ 'Software'), to deal in the Software without restriction, including
158
+ without limitation the rights to use, copy, modify, merge, publish,
159
+ distribute, sublicense, and/or sell copies of the Software, and to
160
+ permit persons to whom the Software is furnished to do so, subject to
161
+ the following conditions:
162
+
163
+ The above copyright notice and this permission notice shall be
164
+ included in all copies or substantial portions of the Software.
165
+
166
+ THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND,
167
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
168
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
169
+ IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
170
+ CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
171
+ TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
172
+ SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
@@ -0,0 +1,22 @@
1
+ # -*- ruby -*-
2
+
3
+ require 'rubygems'
4
+
5
+ begin
6
+ require 'jeweler'
7
+ Jeweler::Tasks.new do |gem|
8
+ gem.name = "ruby-gmail"
9
+ gem.summary = %Q{A Rubyesque interface to Gmail, with all the tools you'll need.}
10
+ gem.description = %Q{A Rubyesque interface to Gmail, with all the tools you'll need. Search, read and send multipart emails; archive, mark as read/unread, delete emails; and manage labels.}
11
+ gem.email = "gems@behindlogic.com"
12
+ gem.homepage = "http://dcparker.github.com/ruby-gmail"
13
+ gem.authors = ["BehindLogic"]
14
+ gem.post_install_message = "\n\033[34mIf ruby-gmail saves you TWO hours of work, want to compensate me for, like, a half-hour?\nSupport me in making new and better gems:\033[0m \033[31;4mhttp://pledgie.com/campaigns/7087\033[0m\n\n"
15
+ gem.add_dependency('shared-mime-info', '>= 0')
16
+ gem.add_dependency('mail', '>= 2.2.1')
17
+ # gem is a Gem::Specification... see http://www.rubygems.org/read/chapter/20 for additional settings
18
+ end
19
+ Jeweler::GemcutterTasks.new
20
+ rescue LoadError
21
+ puts "Jeweler (or a dependency) not available. Install it with: gem install jeweler"
22
+ end
data/VERSION ADDED
@@ -0,0 +1 @@
1
+ 0.2.0
@@ -0,0 +1,168 @@
1
+ require 'net/imap'
2
+
3
+ class Gmail
4
+ VERSION = '0.0.9'
5
+
6
+ class NoLabel < RuntimeError; end
7
+
8
+ ##################################
9
+ # Gmail.new(username, password)
10
+ ##################################
11
+ def initialize(username, password)
12
+ # This is to hide the username and password, not like it REALLY needs hiding, but ... you know.
13
+ # Could be helpful when demoing the gem in irb, these bits won't show up that way.
14
+ class << self
15
+ class << self
16
+ attr_accessor :username, :password
17
+ end
18
+ end
19
+ meta.username = username =~ /@/ ? username : username + '@gmail.com'
20
+ meta.password = password
21
+ @imap = Net::IMAP.new('imap.gmail.com',993,true,nil,false)
22
+ if block_given?
23
+ login # This is here intentionally. Normally, we get auto logged-in when first needed.
24
+ yield self
25
+ logout
26
+ end
27
+ end
28
+
29
+ ###########################
30
+ # READING EMAILS
31
+ #
32
+ # gmail.inbox
33
+ # gmail.label('News')
34
+ #
35
+ ###########################
36
+
37
+ def inbox
38
+ in_label('inbox')
39
+ end
40
+
41
+ def create_label(name)
42
+ imap.create(name)
43
+ end
44
+
45
+ # List the available labels
46
+ def labels
47
+ (imap.list("", "%") + imap.list("[Gmail]/", "%")).inject([]) { |labels,label|
48
+ label[:name].each_line { |l| labels << l }; labels }
49
+ end
50
+
51
+ # gmail.label(name)
52
+ def label(name)
53
+ mailboxes[name] ||= Mailbox.new(self, mailbox)
54
+ end
55
+ alias :mailbox :label
56
+
57
+ ###########################
58
+ # MAKING EMAILS
59
+ #
60
+ # gmail.generate_message do
61
+ # ...inside Mail context...
62
+ # end
63
+ #
64
+ # gmail.deliver do ... end
65
+ #
66
+ # mail = Mail.new...
67
+ # gmail.deliver!(mail)
68
+ ###########################
69
+ def generate_message(&block)
70
+ require 'net/smtp'
71
+ require 'smtp_tls'
72
+ require 'mail'
73
+ mail = Mail.new(&block)
74
+ mail.delivery_method(*smtp_settings)
75
+ mail
76
+ end
77
+
78
+ def deliver(mail=nil, &block)
79
+ require 'net/smtp'
80
+ require 'smtp_tls'
81
+ require 'mail'
82
+ mail = Mail.new(&block) if block_given?
83
+ mail.delivery_method(*smtp_settings)
84
+ mail.from = meta.username unless mail.from
85
+ mail.deliver!
86
+ end
87
+
88
+ ###########################
89
+ # LOGIN
90
+ ###########################
91
+ def login
92
+ res = @imap.login(meta.username, meta.password)
93
+ @logged_in = true if res.name == 'OK'
94
+ end
95
+ def logged_in?
96
+ !!@logged_in
97
+ end
98
+ # Log out of gmail
99
+ def logout
100
+ if logged_in?
101
+ res = @imap.logout
102
+ @logged_in = false if res.name == 'OK'
103
+ end
104
+ end
105
+
106
+ def in_mailbox(mailbox, &block)
107
+ if block_given?
108
+ mailbox_stack << mailbox
109
+ unless @selected == mailbox.name
110
+ imap.select(mailbox.name)
111
+ @selected = mailbox.name
112
+ end
113
+ value = block.arity == 1 ? block.call(mailbox) : block.call
114
+ mailbox_stack.pop
115
+ # Select previously selected mailbox if there is one
116
+ if mailbox_stack.last
117
+ imap.select(mailbox_stack.last.name)
118
+ @selected = mailbox.name
119
+ end
120
+ return value
121
+ else
122
+ mailboxes[name] ||= Mailbox.new(self, mailbox)
123
+ end
124
+ end
125
+ alias :in_label :in_mailbox
126
+
127
+ ###########################
128
+ # Other...
129
+ ###########################
130
+ def inspect
131
+ "#<Gmail:#{'0x%x' % (object_id << 1)} (#{meta.username}) #{'dis' if !logged_in?}connected>"
132
+ end
133
+
134
+ # Accessor for @imap, but ensures that it's logged in first.
135
+ def imap
136
+ unless logged_in?
137
+ login
138
+ at_exit { logout } # Set up auto-logout for later.
139
+ end
140
+ @imap
141
+ end
142
+
143
+ private
144
+ def mailboxes
145
+ @mailboxes ||= {}
146
+ end
147
+ def mailbox_stack
148
+ @mailbox_stack ||= []
149
+ end
150
+ def meta
151
+ class << self; self end
152
+ end
153
+ def domain
154
+ meta.username.split('@')[0]
155
+ end
156
+ def smtp_settings
157
+ [:smtp, {:address => "smtp.gmail.com",
158
+ :port => 587,
159
+ :domain => domain,
160
+ :user_name => meta.username,
161
+ :password => meta.password,
162
+ :authentication => 'plain',
163
+ :enable_starttls_auto => true}]
164
+ end
165
+ end
166
+
167
+ require 'gmail/mailbox'
168
+ require 'gmail/message'
@@ -0,0 +1,71 @@
1
+ require 'date'
2
+ require 'time'
3
+ class Object
4
+ def to_imap_date
5
+ Date.parse(to_s).strftime("%d-%B-%Y")
6
+ end
7
+ end
8
+
9
+ class Gmail
10
+ class Mailbox
11
+ attr_reader :name
12
+
13
+ def initialize(gmail, name)
14
+ @gmail = gmail
15
+ @name = name
16
+ end
17
+
18
+ def inspect
19
+ "<#Mailbox name=#{@name}>"
20
+ end
21
+
22
+ def to_s
23
+ name
24
+ end
25
+
26
+ # Method: emails
27
+ # Args: [ :all | :unread | :read ]
28
+ # Opts: {:since => Date.new}
29
+ def emails(key_or_opts = :all, opts={})
30
+ if key_or_opts.is_a?(Hash) && opts.empty?
31
+ search = ['ALL']
32
+ opts = key_or_opts
33
+ elsif key_or_opts.is_a?(Symbol) && opts.is_a?(Hash)
34
+ aliases = {
35
+ :all => ['ALL'],
36
+ :unread => ['UNSEEN'],
37
+ :read => ['SEEN']
38
+ }
39
+ search = aliases[key_or_opts]
40
+ elsif key_or_opts.is_a?(Array) && opts.empty?
41
+ search = key_or_opts
42
+ else
43
+ raise ArgumentError, "Couldn't make sense of arguments to #emails - should be an optional hash of options preceded by an optional read-status bit; OR simply an array of parameters to pass directly to the IMAP uid_search call."
44
+ end
45
+ if !opts.empty?
46
+ # Support for several search macros
47
+ # :before => Date, :on => Date, :since => Date, :from => String, :to => String
48
+ search.concat ['SINCE', opts[:after].to_imap_date] if opts[:after]
49
+ search.concat ['BEFORE', opts[:before].to_imap_date] if opts[:before]
50
+ search.concat ['ON', opts[:on].to_imap_date] if opts[:on]
51
+ search.concat ['FROM', opts[:from]] if opts[:from]
52
+ search.concat ['TO', opts[:to]] if opts[:to]
53
+ end
54
+
55
+ # puts "Gathering #{(aliases[key] || key).inspect} messages for mailbox '#{name}'..."
56
+ @gmail.in_mailbox(self) do
57
+ @gmail.imap.uid_search(search).collect { |uid| messages[uid] ||= Message.new(@gmail, self, uid) }
58
+ end
59
+ end
60
+
61
+ # This is a convenience method that really probably shouldn't need to exist, but it does make code more readable
62
+ # if seriously all you want is the count of messages.
63
+ def count(*args)
64
+ emails(*args).length
65
+ end
66
+
67
+ def messages
68
+ @messages ||= {}
69
+ end
70
+ end
71
+ end
@@ -0,0 +1,104 @@
1
+ #require 'mime/message'
2
+ class Gmail
3
+ class Message
4
+ def initialize(gmail, mailbox, uid)
5
+ @gmail = gmail
6
+ @mailbox = mailbox
7
+ @uid = uid
8
+ end
9
+
10
+ def inspect
11
+ "<#Message:#{object_id} mailbox=#{@mailbox.name}#{' uid='+@uid.to_s if @uid}#{' message_id='+@message_id.to_s if @message_id}>"
12
+ end
13
+
14
+ # Auto IMAP info
15
+ def uid
16
+ @uid ||= @gmail.imap.uid_search(['HEADER', 'Message-ID', message_id])[0]
17
+ end
18
+
19
+ # IMAP Operations
20
+ def flag(flg)
21
+ @gmail.in_mailbox(@mailbox) do
22
+ @gmail.imap.uid_store(uid, "+FLAGS", [flg])
23
+ end ? true : false
24
+ end
25
+
26
+ def unflag(flg)
27
+ @gmail.in_mailbox(@mailbox) do
28
+ @gmail.imap.uid_store(uid, "-FLAGS", [flg])
29
+ end ? true : false
30
+ end
31
+
32
+ # Gmail Operations
33
+ def mark(flag)
34
+ case flag
35
+ when :read
36
+ flag(:Seen)
37
+ when :unread
38
+ unflag(:Seen)
39
+ when :deleted
40
+ flag(:Deleted)
41
+ when :spam
42
+ move_to('[Gmail]/Spam')
43
+ end ? true : false
44
+ end
45
+
46
+ def delete!
47
+ @mailbox.messages.delete(uid)
48
+ flag(:Deleted)
49
+ end
50
+
51
+ def label(name)
52
+ @gmail.in_mailbox(@mailbox) do
53
+ begin
54
+ @gmail.imap.uid_copy(uid, name)
55
+ rescue Net::IMAP::NoResponseError
56
+ raise Gmail::NoLabel, "No label `#{name}' exists!"
57
+ end
58
+ end
59
+ end
60
+
61
+ def label!(name)
62
+ @gmail.in_mailbox(@mailbox) do
63
+ begin
64
+ @gmail.imap.uid_copy(uid, name)
65
+ rescue Net::IMAP::NoResponseError
66
+ # need to create the label first
67
+ @gmail.create_label(name)
68
+ retry
69
+ end
70
+ end
71
+ end
72
+
73
+ # We're not sure of any 'labels' except the 'mailbox' we're in at the moment.
74
+ # Research whether we can find flags that tell which other labels this email is a part of.
75
+ # def remove_label(name)
76
+ # end
77
+
78
+ def move_to(name)
79
+ label(name) && delete!
80
+ end
81
+
82
+ def archive!
83
+ move_to('[Gmail]/All Mail')
84
+ end
85
+
86
+ private
87
+
88
+ # Parsed MIME message object
89
+ def message
90
+ require 'mail'
91
+ _body = @gmail.in_mailbox(@mailbox) { @gmail.imap.uid_fetch(uid, "RFC822")[0].attr["RFC822"] }
92
+ @message ||= Mail.new(_body)
93
+ end
94
+
95
+ # Delegate all other methods to the Mail message
96
+ def method_missing(*args, &block)
97
+ if block_given?
98
+ message.send(*args, &block)
99
+ else
100
+ message.send(*args)
101
+ end
102
+ end
103
+ end
104
+ end
@@ -0,0 +1,94 @@
1
+ require "openssl"
2
+ require "net/smtp"
3
+
4
+ Net::SMTP.class_eval do
5
+
6
+ def self.start( address, port = nil,
7
+ helo = 'localhost.localdomain',
8
+ user = nil, secret = nil, authtype = nil, use_tls = false,
9
+ &block) # :yield: smtp
10
+ new(address, port).start(helo, user, secret, authtype, use_tls, &block)
11
+ end
12
+
13
+ def start( helo = 'localhost.localdomain',
14
+ user = nil, secret = nil, authtype = nil ) # :yield: smtp
15
+ start_method = starttls_auto? ? :do_tls_start : :do_start
16
+ if block_given?
17
+ begin
18
+ send(start_method, helo, user, secret, authtype)
19
+ return yield(self)
20
+ ensure
21
+ do_finish
22
+ end
23
+ else
24
+ send(start_method, helo, user, secret, authtype)
25
+ return self
26
+ end
27
+ end
28
+
29
+ private
30
+
31
+ def do_tls_start(helodomain, user, secret, authtype)
32
+ raise IOError, 'SMTP session already started' if @started
33
+ if RUBY_VERSION == '1.8.6'
34
+ check_auth_args(user, secret, authtype) if user or secret
35
+ else
36
+ check_auth_args(user, secret) if user or secret
37
+ end
38
+
39
+ sock = timeout(@open_timeout) { TCPSocket.open(@address, @port) }
40
+ @socket = Net::InternetMessageIO.new(sock)
41
+ @socket.read_timeout = 60 #@read_timeout
42
+ @socket.debug_output = STDERR #@debug_output
43
+
44
+ check_response(critical { recv_response() })
45
+ do_helo(helodomain)
46
+
47
+ raise 'openssl library not installed' unless defined?(OpenSSL)
48
+ starttls
49
+ ssl = OpenSSL::SSL::SSLSocket.new(sock)
50
+ ssl.sync_close = true
51
+ ssl.connect
52
+ @socket = Net::InternetMessageIO.new(ssl)
53
+ @socket.read_timeout = 60 #@read_timeout
54
+ @socket.debug_output = STDERR #@debug_output
55
+ do_helo(helodomain)
56
+
57
+ authenticate user, secret, authtype if user
58
+ @started = true
59
+ ensure
60
+ unless @started
61
+ # authentication failed, cancel connection.
62
+ @socket.close if not @started and @socket and not @socket.closed?
63
+ @socket = nil
64
+ end
65
+ end
66
+
67
+ def do_helo(helodomain)
68
+ begin
69
+ if @esmtp
70
+ ehlo helodomain
71
+ else
72
+ helo helodomain
73
+ end
74
+ rescue Net::ProtocolError
75
+ if @esmtp
76
+ @esmtp = false
77
+ @error_occured = false
78
+ retry
79
+ end
80
+ raise
81
+ end
82
+ end
83
+
84
+ def starttls
85
+ getok('STARTTLS')
86
+ end
87
+
88
+ def quit
89
+ begin
90
+ getok('QUIT')
91
+ rescue EOFError, OpenSSL::SSL::SSLError
92
+ end
93
+ end
94
+ end
@@ -0,0 +1,65 @@
1
+ # Generated by jeweler
2
+ # DO NOT EDIT THIS FILE DIRECTLY
3
+ # Instead, edit Jeweler::Tasks in Rakefile, and run the gemspec command
4
+ # -*- encoding: utf-8 -*-
5
+
6
+ Gem::Specification.new do |s|
7
+ s.name = %q{pauldix-ruby-gmail}
8
+ s.version = "0.2.0"
9
+
10
+ s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
11
+ s.authors = ["BehindLogic"]
12
+ s.date = %q{2010-07-01}
13
+ s.description = %q{A Rubyesque interface to Gmail, with all the tools you'll need. Search, read and send multipart emails; archive, mark as read/unread, delete emails; and manage labels.}
14
+ s.email = %q{gems@behindlogic.com}
15
+ s.extra_rdoc_files = [
16
+ "README.markdown"
17
+ ]
18
+ s.files = [
19
+ ".autotest",
20
+ ".gitignore",
21
+ "History.txt",
22
+ "Manifest.txt",
23
+ "README.markdown",
24
+ "Rakefile",
25
+ "VERSION",
26
+ "lib/gmail.rb",
27
+ "lib/gmail/mailbox.rb",
28
+ "lib/gmail/message.rb",
29
+ "lib/smtp_tls.rb",
30
+ "ruby-gmail.gemspec",
31
+ "test/test_gmail.rb",
32
+ "test/test_helper.rb"
33
+ ]
34
+ s.homepage = %q{http://dcparker.github.com/ruby-gmail}
35
+ s.post_install_message = %q{
36
+ If ruby-gmail saves you TWO hours of work, want to compensate me for, like, a half-hour?
37
+ Support me in making new and better gems: http://pledgie.com/campaigns/7087
38
+
39
+ }
40
+ s.rdoc_options = ["--charset=UTF-8"]
41
+ s.require_paths = ["lib"]
42
+ s.rubygems_version = %q{1.3.6}
43
+ s.summary = %q{A Rubyesque interface to Gmail, with all the tools you'll need.}
44
+ s.test_files = [
45
+ "test/test_gmail.rb",
46
+ "test/test_helper.rb"
47
+ ]
48
+
49
+ if s.respond_to? :specification_version then
50
+ current_version = Gem::Specification::CURRENT_SPECIFICATION_VERSION
51
+ s.specification_version = 3
52
+
53
+ if Gem::Version.new(Gem::RubyGemsVersion) >= Gem::Version.new('1.2.0') then
54
+ s.add_runtime_dependency(%q<shared-mime-info>, [">= 0"])
55
+ s.add_runtime_dependency(%q<mail>, [">= 2.2.1"])
56
+ else
57
+ s.add_dependency(%q<shared-mime-info>, [">= 0"])
58
+ s.add_dependency(%q<mail>, [">= 2.2.1"])
59
+ end
60
+ else
61
+ s.add_dependency(%q<shared-mime-info>, [">= 0"])
62
+ s.add_dependency(%q<mail>, [">= 2.2.1"])
63
+ end
64
+ end
65
+
@@ -0,0 +1,72 @@
1
+ require 'test_helper'
2
+
3
+ class GmailTest < Test::Unit::TestCase
4
+ def test_initialize
5
+ imap = mock('imap')
6
+ Net::IMAP.expects(:new).with('imap.gmail.com', 993, true, nil, false).returns(imap)
7
+ gmail = Gmail.new('test', 'password')
8
+ end
9
+
10
+ def test_imap_does_login
11
+ setup_mocks(:at_exit => true)
12
+
13
+ @imap.expects(:disconnected?).at_least_once.returns(true).then.returns(false)
14
+ @imap.expects(:login).with('test@gmail.com', 'password')
15
+ @gmail.imap
16
+ end
17
+
18
+ def test_imap_does_login_only_once
19
+ setup_mocks(:at_exit => true)
20
+
21
+ @imap.expects(:disconnected?).at_least_once.returns(true).then.returns(false)
22
+ @imap.expects(:login).with('test@gmail.com', 'password')
23
+ @gmail.imap
24
+ @gmail.imap
25
+ @gmail.imap
26
+ end
27
+
28
+ def test_imap_does_login_without_appending_gmail_domain
29
+ setup_mocks(:at_exit => true)
30
+
31
+ @imap.expects(:disconnected?).at_least_once.returns(true).then.returns(false)
32
+ @imap.expects(:login).with('test@gmail.com', 'password')
33
+ @gmail.imap
34
+ end
35
+
36
+ def test_imap_logs_out
37
+ setup_mocks(:at_exit => true)
38
+
39
+ @imap.expects(:disconnected?).at_least_once.returns(true).then.returns(false)
40
+ @imap.expects(:login).with('test@gmail.com', 'password')
41
+ @gmail.imap
42
+ @imap.expects(:logout).returns(true)
43
+ @gmail.logout
44
+ end
45
+
46
+ def test_imap_logout_does_nothing_if_not_logged_in
47
+ setup_mocks
48
+
49
+ @imap.expects(:disconnected?).returns(true)
50
+ @imap.expects(:logout).never
51
+ @gmail.logout
52
+ end
53
+
54
+ def test_imap_calls_create_label
55
+ setup_mocks(:at_exit => true)
56
+ @imap.expects(:disconnected?).at_least_once.returns(true).then.returns(false)
57
+ @imap.expects(:login).with('test@gmail.com', 'password')
58
+ @imap.expects(:create).with('foo')
59
+ @gmail.create_label('foo')
60
+ end
61
+
62
+ private
63
+ def setup_mocks(options = {})
64
+ options = {:at_exit => false}.merge(options)
65
+ @imap = mock('imap')
66
+ Net::IMAP.expects(:new).with('imap.gmail.com', 993, true, nil, false).returns(@imap)
67
+ @gmail = Gmail.new('test@gmail.com', 'password')
68
+
69
+ # need this for the at_exit block that auto-exits after this test method completes
70
+ @imap.expects(:logout).at_least(0) if options[:at_exit]
71
+ end
72
+ end
@@ -0,0 +1,4 @@
1
+ require 'test/unit'
2
+ require 'rubygems'
3
+ require 'mocha'
4
+ require 'gmail'
metadata ADDED
@@ -0,0 +1,103 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: pauldix-ruby-gmail
3
+ version: !ruby/object:Gem::Version
4
+ prerelease: false
5
+ segments:
6
+ - 0
7
+ - 2
8
+ - 0
9
+ version: 0.2.0
10
+ platform: ruby
11
+ authors:
12
+ - BehindLogic
13
+ autorequire:
14
+ bindir: bin
15
+ cert_chain: []
16
+
17
+ date: 2010-07-01 00:00:00 -04:00
18
+ default_executable:
19
+ dependencies:
20
+ - !ruby/object:Gem::Dependency
21
+ name: shared-mime-info
22
+ prerelease: false
23
+ requirement: &id001 !ruby/object:Gem::Requirement
24
+ requirements:
25
+ - - ">="
26
+ - !ruby/object:Gem::Version
27
+ segments:
28
+ - 0
29
+ version: "0"
30
+ type: :runtime
31
+ version_requirements: *id001
32
+ - !ruby/object:Gem::Dependency
33
+ name: mail
34
+ prerelease: false
35
+ requirement: &id002 !ruby/object:Gem::Requirement
36
+ requirements:
37
+ - - ">="
38
+ - !ruby/object:Gem::Version
39
+ segments:
40
+ - 2
41
+ - 2
42
+ - 1
43
+ version: 2.2.1
44
+ type: :runtime
45
+ version_requirements: *id002
46
+ description: A Rubyesque interface to Gmail, with all the tools you'll need. Search, read and send multipart emails; archive, mark as read/unread, delete emails; and manage labels.
47
+ email: gems@behindlogic.com
48
+ executables: []
49
+
50
+ extensions: []
51
+
52
+ extra_rdoc_files:
53
+ - README.markdown
54
+ files:
55
+ - .autotest
56
+ - .gitignore
57
+ - History.txt
58
+ - Manifest.txt
59
+ - README.markdown
60
+ - Rakefile
61
+ - VERSION
62
+ - lib/gmail.rb
63
+ - lib/gmail/mailbox.rb
64
+ - lib/gmail/message.rb
65
+ - lib/smtp_tls.rb
66
+ - ruby-gmail.gemspec
67
+ - test/test_gmail.rb
68
+ - test/test_helper.rb
69
+ has_rdoc: true
70
+ homepage: http://dcparker.github.com/ruby-gmail
71
+ licenses: []
72
+
73
+ post_install_message: "\n\
74
+ \e[34mIf ruby-gmail saves you TWO hours of work, want to compensate me for, like, a half-hour?\n\
75
+ Support me in making new and better gems:\e[0m \e[31;4mhttp://pledgie.com/campaigns/7087\e[0m\n\n"
76
+ rdoc_options:
77
+ - --charset=UTF-8
78
+ require_paths:
79
+ - lib
80
+ required_ruby_version: !ruby/object:Gem::Requirement
81
+ requirements:
82
+ - - ">="
83
+ - !ruby/object:Gem::Version
84
+ segments:
85
+ - 0
86
+ version: "0"
87
+ required_rubygems_version: !ruby/object:Gem::Requirement
88
+ requirements:
89
+ - - ">="
90
+ - !ruby/object:Gem::Version
91
+ segments:
92
+ - 0
93
+ version: "0"
94
+ requirements: []
95
+
96
+ rubyforge_project:
97
+ rubygems_version: 1.3.6
98
+ signing_key:
99
+ specification_version: 3
100
+ summary: A Rubyesque interface to Gmail, with all the tools you'll need.
101
+ test_files:
102
+ - test/test_gmail.rb
103
+ - test/test_helper.rb