-
Notifications
You must be signed in to change notification settings - Fork 120
Home
Keith Schacht edited this page Dec 30, 2017
·
8 revisions
Here is an example of working code which may help someone else.
System:
- Ruby 2.3.5
- On a Mac with Chrome installed, it will launch Chrome to authenticate
Notables:
- The oauth2 code is adapted from Google's example for the Google API, the SCOPE needed to be changed to authenticate for IMAP. Every 60 minutes you have to re-authenticate, I could not figure out how to fix that
- I didn't want email messages I wanted conversations so I wrote a couple classes that fake conversations
- The reason I use
gmail.mailbox(...)
rather thangmail.inbox.
is because it's required in order for.archive!
to work. If you're in the inbox view you can't remove a message from the inbox view.
require 'google/apis/gmail_v1'
require 'googleauth'
require 'googleauth/stores/file_token_store'
require 'gmail'
require 'fileutils'
require 'forwardable'
require 'set'
OOB_URI = 'urn:ietf:wg:oauth:2.0:oob'
APPLICATION_NAME = 'Taskmaster'
CLIENT_SECRETS_PATH = 'client_secret.json'
CREDENTIALS_PATH = File.join(Dir.home, '.credentials',
"taskmaster.yaml")
SCOPE = "https://mail.google.com/" # gmail API: Google::Apis::GmailV1::AUTH_GMAIL_MODIFY
class GmailAuthorize
def token; @service.authorization.access_token; end
def initialize
# Initialize the API
@service = Google::Apis::GmailV1::GmailService.new
@service.client_options.application_name = APPLICATION_NAME
@service.authorization = authorize
@service.authorization.access_token
end
##
# Ensure valid credentials, either by restoring from the saved credentials
# files or intitiating an OAuth2 authorization. If authorization is required,
# the user's default browser will be launched to approve the request.
#
# @return [Google::Auth::UserRefreshCredentials] OAuth2 credentials
def authorize
FileUtils.mkdir_p(File.dirname(CREDENTIALS_PATH))
client_id = Google::Auth::ClientId.from_file(CLIENT_SECRETS_PATH)
token_store = Google::Auth::Stores::FileTokenStore.new(file: CREDENTIALS_PATH)
authorizer = Google::Auth::UserAuthorizer.new(
client_id, SCOPE, token_store)
user_id = 'default'
credentials = authorizer.get_credentials(user_id)
if credentials.nil? || credentials.expires_at < Time.now
url = authorizer.get_authorization_url(
base_url: OOB_URI)
puts "Open the following URL in the browser and enter the " +
"resulting code after authorization"
puts url
system("/usr/bin/open -a '/Applications/Google Chrome.app' '#{url}'")
print "paste response: "
code = gets
credentials = authorizer.get_and_store_credentials_from_code(
user_id: user_id, code: code, base_url: OOB_URI)
end
credentials
end
end
class Conversations
include Enumerable
extend Forwardable
def_delegators :to_a, :each, :<<, :[], :collect, :select, :first, :last, :count,
:length; :reverse
def to_a; @conversations.values; end
def initialize(emails)
@emails = emails
@conversations = {}
emails.reverse.each_with_index do |email, i|
print "#{i+1}.."
if @conversations.has_key?(email.thr_id)
@conversations[email.thr_id].add_email(email)
else
@conversations[email.thr_id] = Conversation.new(email)
end
end
end
def inspect
"#<Conversations count=#{count}>"
end
end
class Conversation
def emails; @emails.values; end
def subject; @subject; end
def full_name; @full_name; end
def labels; @labels; end
def label; @labels.first; end
def id; @id; end
def permalink; "https://mail.google.com/mail/#all/#{@id.to_i.to_s(16)}"; end
def length; @emails.keys.length; end
def initialize(email)
@emails = {}
@subject = email.subject
@full_name = email.from.first.name
@id = email.thr_id
@labels = Set.new()
add_email(email)
end
def add_email(email)
@emails[email.msg_id] = email
email.labels.each { |l| @labels << l if l.is_a?(String) }
email
end
def archive!
emails.each { |email| email.archive! }
end
def star!
emails.first.star!
end
def inspect
"#<Conversation id=#{id} length=#{length} subject=#{subject}>"
end
end
puts "Checking inbox..."
gmail = Gmail.connect(:xoauth2, "[email protected]", GmailAuthorize.new.token)
puts gmail.mailbox('[Gmail]/All Mail').emails(gm: 'in:inbox').count
conversations = Conversations.new(gmail.mailbox('[Gmail]/All Mail').emails(gm: 'in:inbox'))