gmail 0.6.0 → 0.7.0

Sign up to get free protection for your applications and to get access to all the features.
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