gmail 0.6.0 → 0.7.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (94) hide show
  1. checksums.yaml +4 -4
  2. data/.coveralls.yml +1 -0
  3. data/.gitignore +27 -27
  4. data/.rspec +1 -1
  5. data/.rubocop.yml +53 -13
  6. data/.rubocop_todo.yml +299 -239
  7. data/.travis.yml +19 -19
  8. data/CHANGELOG.md +152 -145
  9. data/Gemfile +5 -3
  10. data/LICENSE +21 -21
  11. data/README.md +380 -355
  12. data/Rakefile +44 -46
  13. data/gmail.gemspec +32 -34
  14. data/lib/gmail.rb +72 -78
  15. data/lib/gmail/client.rb +35 -34
  16. data/lib/gmail/client/base.rb +244 -229
  17. data/lib/gmail/client/plain.rb +24 -24
  18. data/lib/gmail/client/xoauth.rb +67 -68
  19. data/lib/gmail/client/xoauth2.rb +39 -39
  20. data/lib/gmail/imap_extensions.rb +156 -159
  21. data/lib/gmail/labels.rb +80 -79
  22. data/lib/gmail/mailbox.rb +178 -175
  23. data/lib/gmail/message.rb +212 -207
  24. data/lib/gmail/version.rb +3 -3
  25. data/spec/account.yml.example +1 -1
  26. data/spec/account.yml.obfus +2 -2
  27. data/spec/gmail/client/base_spec.rb +5 -5
  28. data/spec/gmail/client/plain_spec.rb +169 -169
  29. data/spec/gmail/client/xoauth2_spec.rb +186 -186
  30. data/spec/gmail/client/xoauth_spec.rb +5 -5
  31. data/spec/gmail/client_spec.rb +5 -5
  32. data/spec/gmail/imap_extensions_spec.rb +47 -47
  33. data/spec/gmail/labels_spec.rb +27 -27
  34. data/spec/gmail/mailbox_spec.rb +84 -84
  35. data/spec/gmail/message_spec.rb +181 -181
  36. data/spec/gmail_spec.rb +40 -39
  37. data/spec/recordings/gmail/_new_connects_with_client_and_give_it_context_when_block_given.yml +61 -28
  38. data/spec/recordings/gmail/_new_connects_with_gmail_service_and_return_valid_connection_object.yml +43 -28
  39. data/spec/recordings/gmail/_new_does_not_raise_error_when_couldn_t_connect_with_given_account.yml +21 -13
  40. data/spec/recordings/gmail/_new_raises_error_when_couldn_t_connect_with_given_account.yml +21 -13
  41. data/spec/recordings/gmail_client_plain/instance/delivers_inline_composed_email.yml +61 -42
  42. data/spec/recordings/gmail_client_plain/instance/does_not_log_in_when_given_gmail_account_is_invalid.yml +21 -13
  43. data/spec/recordings/gmail_client_plain/instance/does_not_raise_error_even_though_gmail_account_is_invalid.yml +21 -13
  44. data/spec/recordings/gmail_client_plain/instance/labels/checks_if_there_is_given_label_defined.yml +409 -196
  45. data/spec/recordings/gmail_client_plain/instance/labels/creates_given_label.yml +280 -151
  46. data/spec/recordings/gmail_client_plain/instance/labels/removes_existing_label.yml +271 -146
  47. data/spec/recordings/gmail_client_plain/instance/labels/returns_list_of_all_available_labels.yml +227 -113
  48. data/spec/recordings/gmail_client_plain/instance/properly_logs_in_to_valid_gmail_account.yml +61 -42
  49. data/spec/recordings/gmail_client_plain/instance/properly_logs_out_from_gmail.yml +61 -42
  50. data/spec/recordings/gmail_client_plain/instance/properly_switches_to_given_mailbox.yml +164 -109
  51. data/spec/recordings/gmail_client_plain/instance/properly_switches_to_given_mailbox_using_block_style.yml +164 -109
  52. data/spec/recordings/gmail_client_plain/instance/raises_error_when_given_gmail_account_is_invalid_and_errors_enabled.yml +21 -13
  53. data/spec/recordings/gmail_client_xo_auth2/instance/does_not_log_in_when_given_gmail_account_is_invalid.yml +24 -13
  54. data/spec/recordings/gmail_client_xo_auth2/instance/labels/checks_if_there_is_given_label_defined.yml +39 -27
  55. data/spec/recordings/gmail_client_xo_auth2/instance/labels/creates_given_label.yml +52 -39
  56. data/spec/recordings/gmail_client_xo_auth2/instance/labels/removes_existing_label.yml +52 -39
  57. data/spec/recordings/gmail_client_xo_auth2/instance/labels/returns_list_of_all_available_labels.yml +39 -27
  58. data/spec/recordings/gmail_client_xo_auth2/instance/properly_logs_in_to_valid_gmail_account.yml +26 -15
  59. data/spec/recordings/gmail_client_xo_auth2/instance/properly_logs_out_from_gmail.yml +26 -15
  60. data/spec/recordings/gmail_client_xo_auth2/instance/properly_switches_to_given_mailbox.yml +63 -40
  61. data/spec/recordings/gmail_client_xo_auth2/instance/properly_switches_to_given_mailbox_using_block_style.yml +63 -40
  62. data/spec/recordings/gmail_client_xo_auth2/instance/raises_error_when_given_gmail_account_is_invalid_and_errors_enabled.yml +24 -13
  63. data/spec/recordings/gmail_labels/localize/when_given_the_xl_is_tflag/all/localizes_into_the_appropriate_label.yml +229 -116
  64. data/spec/recordings/gmail_labels/localize/when_given_the_xl_is_tflag/and_the_mailbox_does_not_exist/returns_the_mailbox_name_as_a_string.yml +229 -110
  65. data/spec/recordings/gmail_labels/localize/when_given_the_xl_is_tflag/drafts/localizes_into_the_appropriate_label.yml +229 -116
  66. data/spec/recordings/gmail_labels/localize/when_given_the_xl_is_tflag/flagged/localizes_into_the_appropriate_label.yml +229 -116
  67. data/spec/recordings/gmail_labels/localize/when_given_the_xl_is_tflag/important/localizes_into_the_appropriate_label.yml +229 -116
  68. data/spec/recordings/gmail_labels/localize/when_given_the_xl_is_tflag/inbox/localizes_into_the_appropriate_label.yml +61 -42
  69. data/spec/recordings/gmail_labels/localize/when_given_the_xl_is_tflag/junk/localizes_into_the_appropriate_label.yml +229 -116
  70. data/spec/recordings/gmail_labels/localize/when_given_the_xl_is_tflag/sent/localizes_into_the_appropriate_label.yml +229 -116
  71. data/spec/recordings/gmail_labels/localize/when_given_the_xl_is_tflag/trash/localizes_into_the_appropriate_label.yml +229 -116
  72. data/spec/recordings/gmail_mailbox/instance/counts_all_emails.yml +595 -277
  73. data/spec/recordings/gmail_mailbox/instance/finds_messages.yml +1049 -586
  74. data/spec/recordings/gmail_mailbox/instance/waits_once.yml +191 -136
  75. data/spec/recordings/gmail_mailbox/instance/waits_repeatedly.yml +217 -141
  76. data/spec/recordings/gmail_mailbox/instance/waits_with_29-minute_re-issue.yml +188 -136
  77. data/spec/recordings/gmail_mailbox/instance/waits_with_an_unblocked_connection.yml +644 -207
  78. data/spec/recordings/gmail_mailbox/on_initialize/sets_client_and_name.yml +61 -42
  79. data/spec/recordings/gmail_mailbox/on_initialize/works_in_inbox_by_default.yml +61 -42
  80. data/spec/recordings/gmail_message/initialize/sets_prefetch_attrs.yml +1068 -578
  81. data/spec/recordings/gmail_message/initialize/sets_uid_and_mailbox.yml +1068 -580
  82. data/spec/recordings/gmail_message/instance_methods/deletes_itself.yml +1084 -637
  83. data/spec/recordings/gmail_message/instance_methods/marks_itself_read.yml +1137 -682
  84. data/spec/recordings/gmail_message/instance_methods/marks_itself_unread.yml +1153 -686
  85. data/spec/recordings/gmail_message/instance_methods/moves_from_one_tag_to_other.yml +1447 -862
  86. data/spec/recordings/gmail_message/instance_methods/removes_a_given_label.yml +1288 -776
  87. data/spec/recordings/gmail_message/instance_methods/removes_a_given_label_with_old_method.yml +1288 -776
  88. data/spec/recordings/gmail_message/instance_methods/sets_given_label.yml +1165 -690
  89. data/spec/recordings/gmail_message/instance_methods/sets_given_label_with_old_method.yml +1157 -691
  90. data/spec/spec_helper.rb +56 -53
  91. data/spec/support/imap_mock.rb +181 -181
  92. data/spec/support/obfuscation.rb +49 -52
  93. metadata +21 -90
  94. data/spec/recordings/gmail_client_plain/instance/_connection_automatically_logs_in_to_gmail_account_when_it_s_called.yml +0 -42
data/Rakefile CHANGED
@@ -1,46 +1,44 @@
1
- #!/usr/bin/env rake
2
-
3
- begin
4
- require 'bundler/setup'
5
- rescue LoadError
6
- puts 'You must `gem install bundler` and `bundle install` to run rake tasks'
7
- end
8
-
9
- begin
10
- require 'rdoc/task'
11
- rescue LoadError
12
- require 'rdoc/rdoc'
13
- require 'rake/rdoctask'
14
- RDoc::Task = Rake::RDocTask
15
- end
16
-
17
- RDoc::Task.new(:rdoc) do |rdoc|
18
- rdoc.rdoc_dir = 'rdoc'
19
- rdoc.title = "Gmail for Ruby #{Gmail::VERSION}"
20
- rdoc.rdoc_files.include('README*')
21
- rdoc.rdoc_files.include('lib/**/*.rb')
22
- end
23
-
24
- Bundler::GemHelper.install_tasks
25
-
26
- begin
27
- require 'rspec/core/rake_task'
28
- RSpec::Core::RakeTask.new(:spec)
29
- rescue LoadError
30
- task :spec do
31
- abort 'Run `gem install rspec` to install RSpec'
32
- end
33
- end
34
-
35
- task :default => :spec
36
-
37
- $LOAD_PATH.unshift(File.dirname(__FILE__))
38
- require 'spec/support/obfuscation'
39
- desc 'Obfuscates account.yml file.'
40
- task :obfuscate do
41
- Spec::Obfuscation.encrypt_file(File.join(File.dirname(__FILE__), 'spec', 'account.yml'))
42
- end
43
-
44
- task :deobfuscate do
45
- puts Spec::Obfuscation.decrypt_file(File.join(File.dirname(__FILE__), 'spec', 'account.yml.obfus'))
46
- end
1
+ begin
2
+ require 'bundler/setup'
3
+ rescue LoadError
4
+ puts 'You must `gem install bundler` and `bundle install` to run rake tasks'
5
+ end
6
+
7
+ begin
8
+ require 'rdoc/task'
9
+ rescue LoadError
10
+ require 'rdoc/rdoc'
11
+ require 'rake/rdoctask'
12
+ RDoc::Task = Rake::RDocTask
13
+ end
14
+
15
+ RDoc::Task.new(:rdoc) do |rdoc|
16
+ rdoc.rdoc_dir = 'rdoc'
17
+ rdoc.title = "Gmail for Ruby #{Gmail::VERSION}"
18
+ rdoc.rdoc_files.include('README*')
19
+ rdoc.rdoc_files.include('lib/**/*.rb')
20
+ end
21
+
22
+ Bundler::GemHelper.install_tasks
23
+
24
+ begin
25
+ require 'rspec/core/rake_task'
26
+ RSpec::Core::RakeTask.new(:spec)
27
+ rescue LoadError
28
+ task :spec do
29
+ abort 'Run `gem install rspec` to install RSpec'
30
+ end
31
+ end
32
+
33
+ task :default => :spec
34
+
35
+ $LOAD_PATH.unshift(File.dirname(__FILE__))
36
+ require 'spec/support/obfuscation'
37
+ desc 'Obfuscates account.yml file.'
38
+ task :obfuscate do
39
+ Spec::Obfuscation.encrypt_file(File.join(File.dirname(__FILE__), 'spec', 'account.yml'))
40
+ end
41
+
42
+ task :deobfuscate do
43
+ puts Spec::Obfuscation.decrypt_file(File.join(File.dirname(__FILE__), 'spec', 'account.yml.obfus'))
44
+ end
@@ -1,34 +1,32 @@
1
- # -*- encoding: utf-8 -*-
2
-
3
- $:.push File.expand_path('../lib', __FILE__)
4
- require 'gmail/version'
5
-
6
- Gem::Specification.new do |s|
7
- s.name = "gmail"
8
- s.summary = "A Rubyesque interface to Gmail, with all the tools you will need."
9
- s.description = "A Rubyesque interface to Gmail, with all the tools you will need.
10
- Search, read and send multipart emails; archive, mark as read/unread,
11
- delete emails; and manage labels.
12
- "
13
- s.version = Gmail::VERSION
14
- s.platform = Gem::Platform::RUBY
15
- s.authors = ["Chris Kowalik"]
16
- s.email = ["chris@nu7hat.ch"]
17
- s.homepage = "http://github.com/gmailgem/gmail"
18
- s.licenses = ["MIT"]
19
-
20
- # runtime dependencies
21
- s.add_dependency "mail", ">= 2.2.1"
22
- s.add_dependency "gmail_xoauth", ">= 0.3.0"
23
-
24
- # development dependencies
25
- s.add_development_dependency "rake"
26
- s.add_development_dependency "rspec", ">= 3.1"
27
- s.add_development_dependency "rubocop"
28
- s.add_development_dependency "gem-release"
29
-
30
- s.files = `git ls-files`.split("\n")
31
- s.test_files = `git ls-files -- {test,spec,features}/*`.split("\n")
32
- s.executables = `git ls-files -- bin/*`.split("\n").map { |f| File.basename(f) }
33
- s.require_paths = ["lib"]
34
- end
1
+ $:.push File.expand_path('../lib', __FILE__)
2
+ require 'gmail/version'
3
+
4
+ Gem::Specification.new do |s|
5
+ s.name = "gmail"
6
+ s.summary = "A Rubyesque interface to Gmail, with all the tools you will need."
7
+ s.description = "A Rubyesque interface to Gmail, with all the tools you will need.
8
+ Search, read and send multipart emails; archive, mark as read/unread,
9
+ delete emails; and manage labels.
10
+ "
11
+ s.version = Gmail::VERSION
12
+ s.platform = Gem::Platform::RUBY
13
+ s.authors = ["Chris Kowalik"]
14
+ s.email = ["chris@nu7hat.ch"]
15
+ s.homepage = "http://github.com/gmailgem/gmail"
16
+ s.licenses = ["MIT"]
17
+
18
+ # runtime dependencies
19
+ s.add_dependency "gmail_xoauth", ">= 0.3.0"
20
+ s.add_dependency "mail", ">= 2.2.1"
21
+
22
+ # development dependencies
23
+ s.add_development_dependency "gem-release"
24
+ s.add_development_dependency "rake"
25
+ s.add_development_dependency "rspec", ">= 3.1"
26
+ s.add_development_dependency "rubocop", ">= 0.34.2"
27
+
28
+ s.files = `git ls-files`.split("\n")
29
+ s.test_files = `git ls-files -- {test,spec,features}/*`.split("\n")
30
+ s.executables = `git ls-files -- bin/*`.split("\n").map { |f| File.basename(f) }
31
+ s.require_paths = ["lib"]
32
+ end
@@ -1,78 +1,72 @@
1
- require 'net/imap'
2
- require 'net/smtp'
3
- require 'mail'
4
- require 'date'
5
- require 'time'
6
-
7
- if RUBY_VERSION < "1.8.7"
8
- require "smtp_tls"
9
- end
10
-
11
- class Object
12
- def to_imap_date
13
- date = respond_to?(:utc) ? utc.to_s : to_s
14
- Date.parse(date).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
- # Creates new Gmail connection using given authorization options.
27
- #
28
- # ==== Examples
29
- #
30
- # Gmail.new(:plain, "foo@gmail.com", "password")
31
- # Gmail.new(:xoauth, "foo@gmail.com",
32
- # :consumer_key => "",
33
- # :consumer_secret => "",
34
- # :token => "",
35
- # :secret => "")
36
- #
37
- # To use plain authentication mehod you can also call:
38
- #
39
- # Gmail.new("foo@gmail.com", "password")
40
- #
41
- # You can also use block-style call:
42
- #
43
- # Gmail.new("foo@gmail.com", "password") do |client|
44
- # # ...
45
- # end
46
- #
47
-
48
- def new(*args, &block)
49
- args.unshift(:plain) unless args.first.is_a?(Symbol)
50
- client = Gmail::Client.new(*args)
51
- client.connect
52
- client.login
53
-
54
- if block_given?
55
- yield client
56
- client.logout
57
- end
58
-
59
- client
60
- end
61
- alias_method :connect, :new
62
-
63
- def new!(*args, &block)
64
- args.unshift(:plain) unless args.first.is_a?(Symbol)
65
- client = Gmail::Client.new(*args)
66
- client.connect!
67
- client.login!
68
-
69
- if block_given?
70
- yield client
71
- client.logout
72
- end
73
-
74
- client
75
- end
76
- alias_method :connect!, :new!
77
- end # << self
78
- end # Gmail
1
+ require 'net/imap'
2
+ require 'net/smtp'
3
+ require 'mail'
4
+ require 'date'
5
+ require 'time'
6
+
7
+ if RUBY_VERSION < "1.8.7"
8
+ require "smtp_tls"
9
+ end
10
+
11
+ module Gmail
12
+ autoload :Version, "gmail/version"
13
+ autoload :Client, "gmail/client"
14
+ autoload :Labels, "gmail/labels"
15
+ autoload :Mailbox, "gmail/mailbox"
16
+ autoload :Message, "gmail/message"
17
+
18
+ class << self
19
+ # Creates new Gmail connection using given authorization options.
20
+ #
21
+ # ==== Examples
22
+ #
23
+ # Gmail.new(:plain, "foo@gmail.com", "password")
24
+ # Gmail.new(:xoauth, "foo@gmail.com",
25
+ # :consumer_key => "",
26
+ # :consumer_secret => "",
27
+ # :token => "",
28
+ # :secret => "")
29
+ #
30
+ # To use plain authentication method you can also call:
31
+ #
32
+ # Gmail.new("foo@gmail.com", "password")
33
+ #
34
+ # You can also use block-style call:
35
+ #
36
+ # Gmail.new("foo@gmail.com", "password") do |client|
37
+ # # ...
38
+ # end
39
+ #
40
+
41
+ def new(*args, &block)
42
+ args.unshift(:plain) unless args.first.is_a?(Symbol)
43
+ client = Gmail::Client.new(*args)
44
+ client.connect
45
+ client.login
46
+
47
+ check_with_block(client, &block)
48
+ end
49
+ alias_method :connect, :new
50
+
51
+ def new!(*args, &block)
52
+ args.unshift(:plain) unless args.first.is_a?(Symbol)
53
+ client = Gmail::Client.new(*args)
54
+ client.connect!
55
+ client.login!
56
+
57
+ check_with_block(client, &block)
58
+ end
59
+ alias_method :connect!, :new!
60
+
61
+ private
62
+
63
+ def check_with_block(client, &block)
64
+ if block_given?
65
+ yield client
66
+ client.logout
67
+ end
68
+
69
+ client
70
+ end
71
+ end # << self
72
+ end # Gmail
@@ -1,34 +1,35 @@
1
- module Gmail
2
- module 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
- # Raised when given client is not registered
10
- class UnknownClient < ArgumentError; end
11
-
12
- def self.clients
13
- @clients ||= {}
14
- end
15
-
16
- def self.register(name, klass)
17
- clients[name] = klass
18
- end
19
-
20
- def self.new(name, *args)
21
- if client = clients[name]
22
- client.new(*args)
23
- else
24
- raise UnknownClient, "No such client: #{name}"
25
- end
26
- end
27
-
28
- require 'gmail/imap_extensions'
29
- require 'gmail/client/base'
30
- require 'gmail/client/plain'
31
- require 'gmail/client/xoauth'
32
- require 'gmail/client/xoauth2'
33
- end # Client
34
- end # Gmail
1
+ module Gmail
2
+ module 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
+ # Raised when given client is not registered
10
+ class UnknownClient < ArgumentError; end
11
+ # Raised when email not found
12
+ class EmailNotFound < ArgumentError; end
13
+
14
+ def self.clients
15
+ @clients ||= {}
16
+ end
17
+
18
+ def self.register(name, klass)
19
+ clients[name] = klass
20
+ end
21
+
22
+ def self.new(name, *args)
23
+ if client = clients[name]
24
+ return client.new(*args)
25
+ end
26
+ raise UnknownClient, "No such client: #{name}"
27
+ end
28
+
29
+ require 'gmail/imap_extensions'
30
+ require 'gmail/client/base'
31
+ require 'gmail/client/plain'
32
+ require 'gmail/client/xoauth'
33
+ require 'gmail/client/xoauth2'
34
+ end # Client
35
+ end # Gmail
@@ -1,229 +1,244 @@
1
- require 'thread'
2
-
3
- module Gmail
4
- module Client
5
- class Base
6
- # Gmail IMAP defaults
7
- GMAIL_IMAP_HOST = 'imap.gmail.com'
8
- GMAIL_IMAP_PORT = 993
9
-
10
- # Gmail SMTP defaults
11
- GMAIL_SMTP_HOST = "smtp.gmail.com"
12
- GMAIL_SMTP_PORT = 587
13
-
14
- attr_reader :username
15
- attr_reader :options
16
-
17
- def initialize(username, options = {})
18
- defaults = {}
19
- @username = fill_username(username)
20
- @options = defaults.merge(options)
21
- @mailbox_mutex = Mutex.new
22
- end
23
-
24
- # Connect to gmail service.
25
- def connect(raise_errors = false)
26
- @imap = Net::IMAP.new(GMAIL_IMAP_HOST, GMAIL_IMAP_PORT, true, nil, false)
27
- Gmail::ImapExtensions.patch_net_imap_response_parser
28
- @imap
29
- rescue SocketError
30
- raise_errors and raise ConnectionError, "Couldn't establish connection with Gmail IMAP service"
31
- end
32
-
33
- # This version of connect will raise error on failure...
34
- def connect!
35
- connect(true)
36
- end
37
-
38
- # Return current connection. Log in automaticaly to specified account if
39
- # it is necessary.
40
- def connection
41
- login and at_exit { logout } unless logged_in?
42
- @imap
43
- end
44
- alias :conn :connection
45
-
46
- # Login to specified account.
47
- def login(*args)
48
- raise NotImplementedError, "The `#{self.class.name}#login` method is not implemented."
49
- end
50
- alias :sign_in :login
51
-
52
- # This version of login will raise error on failure...
53
- def login!
54
- login(true)
55
- end
56
- alias :sign_in! :login!
57
-
58
- # Returns +true+ when you are logged in to specified account.
59
- def logged_in?
60
- !!@logged_in
61
- end
62
- alias :signed_in? :logged_in?
63
-
64
- # Logout from Gmail service.
65
- def logout
66
- @imap && logged_in? and @imap.logout
67
- ensure
68
- @logged_in = false
69
- end
70
- alias :sign_out :logout
71
-
72
- # Disconnect from Gmail service.
73
- def disconnect
74
- @imap && @imap.disconnect
75
- end
76
-
77
- # Return labels object, which helps you with managing your Gmail labels.
78
- # See <tt>Gmail::Labels</tt> for details.
79
- def labels
80
- @labels ||= Labels.new(conn)
81
- end
82
-
83
- # Compose new e-mail.
84
- #
85
- # ==== Examples
86
- #
87
- # mail = gmail.compose
88
- # mail.from "test@gmail.org"
89
- # mail.to "friend@gmail.com"
90
- #
91
- # ... or block style:
92
- #
93
- # mail = gmail.compose do
94
- # from "test@gmail.org"
95
- # to "friend@gmail.com"
96
- # subject "Hello!"
97
- # body "Hello my friend! long time..."
98
- # end
99
- #
100
- # Now you can deliver your mail:
101
- #
102
- # gmail.deliver(mail)
103
- def compose(mail = nil, &block)
104
- if block_given?
105
- mail = Mail.new(&block)
106
- elsif !mail
107
- mail = Mail.new
108
- end
109
-
110
- mail.delivery_method(*smtp_settings)
111
- mail.from = username unless mail.from
112
- mail
113
- end
114
- alias :message :compose
115
-
116
- # Compose (optionaly) and send given email.
117
- #
118
- # ==== Examples
119
- #
120
- # gmail.deliver do
121
- # to "friend@gmail.com"
122
- # subject "Hello friend!"
123
- # body "Hi! How are you?"
124
- # end
125
- #
126
- # ... or with already created message:
127
- #
128
- # mail = Mail.new { ... }
129
- # gmail.deliver(mail)
130
- #
131
- # mail = gmail.compose { ... }
132
- # gmail.deliver(mail)
133
- def deliver(mail = nil, raise_errors = false, &block)
134
- mail = compose(mail, &block)
135
- mail.deliver!
136
- rescue Object => ex
137
- raise_errors and raise DeliveryError, "Couldn't deliver email: #{ex.to_s}"
138
- end
139
-
140
- # This version of deliver will raise error on failure...
141
- def deliver!(mail = nil, &block)
142
- deliver(mail, true, &block)
143
- end
144
-
145
- # Do something with given mailbox or within it context.
146
- #
147
- # ==== Examples
148
- #
149
- # mailbox = gmail.mailbox("INBOX")
150
- # mailbox.emails(:all)
151
- # mailbox.count(:unread, :before => Time.now-(20*24*3600))
152
- #
153
- # ... or block style:
154
- #
155
- # gmail.label("Work") do |mailbox|
156
- # mailbox.emails(:unread)
157
- # mailbox.count(:all)
158
- # ...
159
- # end
160
- def mailbox(name, &block)
161
- @mailbox_mutex.synchronize do
162
- name = labels.localize(name)
163
- mailbox = (mailboxes[name] ||= Mailbox.new(self, name))
164
- switch_to_mailbox(mailbox) if @current_mailbox != mailbox
165
-
166
- if block_given?
167
- mailbox_stack << @current_mailbox
168
- result = block.arity == 1 ? block.call(mailbox) : block.call
169
- mailbox_stack.pop
170
- switch_to_mailbox(mailbox_stack.last)
171
- return result
172
- end
173
-
174
- return mailbox
175
- end
176
- end
177
- alias :in_mailbox :mailbox
178
- alias :in_label :mailbox
179
- alias :label :mailbox
180
-
181
- # Alias for <tt>mailbox("INBOX")</tt>. See <tt>Gmail::Client#mailbox</tt>
182
- # for details.
183
- def inbox
184
- mailbox("INBOX")
185
- end
186
-
187
- def mailboxes
188
- @mailboxes ||= {}
189
- end
190
-
191
- def inspect
192
- "#<Gmail::Client#{'0x%04x' % (object_id << 1)} (#{username}) #{'dis' if !logged_in?}connected>"
193
- end
194
-
195
- def fill_username(username)
196
- username =~ /@/ ? username : "#{username}@gmail.com"
197
- end
198
-
199
- def mail_domain
200
- username.split('@').last
201
- end
202
-
203
- private
204
-
205
- def switch_to_mailbox(mailbox)
206
- if mailbox
207
- conn.select(mailbox.encoded_name)
208
- end
209
- @current_mailbox = mailbox
210
- end
211
-
212
- def mailbox_stack
213
- @mailbox_stack ||= []
214
- end
215
-
216
- def smtp_settings
217
- [:smtp, {
218
- :address => GMAIL_SMTP_HOST,
219
- :port => GMAIL_SMTP_PORT,
220
- :domain => mail_domain,
221
- :user_name => username,
222
- :password => password,
223
- :authentication => 'plain',
224
- :enable_starttls_auto => true
225
- }]
226
- end
227
- end # Base
228
- end # Client
229
- end # Gmail
1
+ module Gmail
2
+ module Client
3
+ class Base
4
+ # Gmail IMAP defaults
5
+ GMAIL_IMAP_HOST = 'imap.gmail.com'.freeze
6
+ GMAIL_IMAP_PORT = 993
7
+
8
+ # Gmail SMTP defaults
9
+ GMAIL_SMTP_HOST = "smtp.gmail.com".freeze
10
+ GMAIL_SMTP_PORT = 587
11
+
12
+ attr_reader :username
13
+ attr_reader :options
14
+
15
+ def initialize(username, options = {})
16
+ defaults = {}
17
+ @username = fill_username(username)
18
+ @options = defaults.merge(options)
19
+ @mailbox_mutex = Mutex.new
20
+ end
21
+
22
+ # Connect to gmail service.
23
+ def connect(raise_errors = false)
24
+ @imap = Net::IMAP.new(GMAIL_IMAP_HOST, GMAIL_IMAP_PORT, true, nil, false)
25
+ Gmail::ImapExtensions.patch_net_imap_response_parser
26
+ @imap
27
+ rescue SocketError
28
+ raise_errors and raise ConnectionError, "Couldn't establish connection with Gmail IMAP service"
29
+ end
30
+
31
+ # This version of connect will raise error on failure...
32
+ def connect!
33
+ connect(true)
34
+ end
35
+
36
+ # Return current connection. Log in automaticaly to specified account if
37
+ # it is necessary.
38
+ def connection
39
+ login and at_exit { logout } unless logged_in?
40
+ @imap
41
+ end
42
+ alias :conn :connection
43
+
44
+ # Login to specified account.
45
+ def login(*args)
46
+ raise NotImplementedError, "The `#{self.class.name}#login` method is not implemented."
47
+ end
48
+ alias :sign_in :login
49
+
50
+ # This version of login will raise error on failure...
51
+ def login!
52
+ login(true)
53
+ end
54
+ alias :sign_in! :login!
55
+
56
+ # Returns +true+ when you are logged in to specified account.
57
+ def logged_in?
58
+ !!@logged_in
59
+ end
60
+ alias :signed_in? :logged_in?
61
+
62
+ # Logout from Gmail service.
63
+ def logout
64
+ @imap && logged_in? and @imap.logout
65
+ ensure
66
+ @logged_in = false
67
+ end
68
+ alias :sign_out :logout
69
+
70
+ # Disconnect from Gmail service.
71
+ def disconnect
72
+ @imap && @imap.disconnect
73
+ end
74
+
75
+ # Return labels object, which helps you with managing your Gmail labels.
76
+ # See <tt>Gmail::Labels</tt> for details.
77
+ def labels
78
+ @labels ||= Labels.new(conn)
79
+ end
80
+
81
+ # Compose new e-mail.
82
+ #
83
+ # ==== Examples
84
+ #
85
+ # mail = gmail.compose
86
+ # mail.from "test@gmail.org"
87
+ # mail.to "friend@gmail.com"
88
+ #
89
+ # ... or block style:
90
+ #
91
+ # mail = gmail.compose do
92
+ # from "test@gmail.org"
93
+ # to "friend@gmail.com"
94
+ # subject "Hello!"
95
+ # body "Hello my friend! long time..."
96
+ # end
97
+ #
98
+ # Now you can deliver your mail:
99
+ #
100
+ # gmail.deliver(mail)
101
+ def compose(mail = nil, &block)
102
+ if block_given?
103
+ mail = Mail.new(&block)
104
+ elsif !mail
105
+ mail = Mail.new
106
+ end
107
+
108
+ mail.delivery_method(*smtp_settings)
109
+ mail.from = username unless mail.from
110
+ mail
111
+ end
112
+ alias :message :compose
113
+
114
+ # Compose (optionaly) and send given email.
115
+ #
116
+ # ==== Examples
117
+ #
118
+ # gmail.deliver do
119
+ # to "friend@gmail.com"
120
+ # subject "Hello friend!"
121
+ # body "Hi! How are you?"
122
+ # end
123
+ #
124
+ # ... or with already created message:
125
+ #
126
+ # mail = Mail.new { ... }
127
+ # gmail.deliver(mail)
128
+ #
129
+ # mail = gmail.compose { ... }
130
+ # gmail.deliver(mail)
131
+ def deliver(mail = nil, raise_errors = false, &block)
132
+ mail = compose(mail, &block)
133
+ mail.deliver!
134
+ rescue Object => ex
135
+ raise_errors and raise DeliveryError, "Couldn't deliver email: #{ex.to_s}"
136
+ end
137
+
138
+ # This version of deliver will raise error on failure...
139
+ def deliver!(mail = nil, &block)
140
+ deliver(mail, true, &block)
141
+ end
142
+
143
+ # Do something with given mailbox or within it context.
144
+ #
145
+ # ==== Examples
146
+ #
147
+ # mailbox = gmail.mailbox("INBOX")
148
+ # mailbox.emails(:all)
149
+ # mailbox.count(:unread, :before => Time.now-(20*24*3600))
150
+ #
151
+ # ... or block style:
152
+ #
153
+ # gmail.label("Work") do |mailbox|
154
+ # mailbox.emails(:unread)
155
+ # mailbox.count(:all)
156
+ # ...
157
+ # end
158
+ def mailbox(name, &block)
159
+ @mailbox_mutex.synchronize do
160
+ name = labels.localize(name)
161
+ mailbox = (mailboxes[name] ||= Mailbox.new(self, name))
162
+ switch_to_mailbox(mailbox) if @current_mailbox != mailbox
163
+
164
+ if block_given?
165
+ mailbox_stack << @current_mailbox
166
+ result = block.arity == 1 ? yield(mailbox) : yield
167
+ mailbox_stack.pop
168
+ switch_to_mailbox(mailbox_stack.last)
169
+ return result
170
+ end
171
+
172
+ return mailbox
173
+ end
174
+ end
175
+ alias :in_mailbox :mailbox
176
+ alias :in_label :mailbox
177
+ alias :label :mailbox
178
+
179
+ # Alias for <tt>mailbox("INBOX")</tt>. See <tt>Gmail::Mailbox</tt>
180
+ # for details.
181
+ def inbox
182
+ mailbox("INBOX")
183
+ end
184
+
185
+ # Functionality like rails #find method
186
+ # https://support.google.com/mail/answer/7190?hl=en
187
+ # Messages with a certain message-id header
188
+ # Rfc822msgid:
189
+ # Example: rfc822msgid:200503292@example.com
190
+ def find(rfc822msgid)
191
+ message = :message_before_built
192
+
193
+ mailbox(:all) do |mailbox|
194
+ uid = conn.uid_search(['X-GM-RAW', "rfc822msgid:#{rfc822msgid.to_s.strip}"]).first
195
+ raise EmailNotFound, "Can't find message with ID #{rfc822msgid}" unless uid
196
+ message = Message.new(mailbox, uid)
197
+ end
198
+
199
+ message
200
+ end
201
+
202
+ def mailboxes
203
+ @mailboxes ||= {}
204
+ end
205
+
206
+ def inspect
207
+ "#<Gmail::Client#{'0x%04x' % (object_id << 1)} (#{username}) #{'dis' if !logged_in?}connected>"
208
+ end
209
+
210
+ def fill_username(username)
211
+ username =~ /@/ ? username : "#{username}@gmail.com"
212
+ end
213
+
214
+ def mail_domain
215
+ username.split('@').last
216
+ end
217
+
218
+ private
219
+
220
+ def switch_to_mailbox(mailbox)
221
+ if mailbox
222
+ conn.select(mailbox.encoded_name)
223
+ end
224
+ @current_mailbox = mailbox
225
+ end
226
+
227
+ def mailbox_stack
228
+ @mailbox_stack ||= []
229
+ end
230
+
231
+ def smtp_settings
232
+ [:smtp, {
233
+ :address => GMAIL_SMTP_HOST,
234
+ :port => GMAIL_SMTP_PORT,
235
+ :domain => mail_domain,
236
+ :user_name => username,
237
+ :password => password,
238
+ :authentication => 'plain',
239
+ :enable_starttls_auto => true
240
+ }]
241
+ end
242
+ end # Base
243
+ end # Client
244
+ end # Gmail