require 'thread' module Gmail module Client class Base # GMail IMAP defaults GMAIL_IMAP_HOST = 'imap.gmail.com' GMAIL_IMAP_PORT = 993 # GMail SMTP defaults GMAIL_SMTP_HOST = "smtp.gmail.com" GMAIL_SMTP_PORT = 587 attr_reader :username attr_reader :options def initialize(username, options={}) defaults = {} @username = fill_username(username) @options = defaults.merge(options) @mailbox_mutex = Mutex.new end # Connect to gmail service. def connect(raise_errors=false) @imap = Net::IMAP.new(GMAIL_IMAP_HOST, GMAIL_IMAP_PORT, true, nil, false) GmailImapExtensions.patch_net_imap_response_parser @imap rescue SocketError raise_errors and raise ConnectionError, "Couldn't establish connection with GMail IMAP service" end # This version of connect will raise error on failure... def connect! connect(true) end # Return current connection. Log in automaticaly to specified account if # it is necessary. def connection login and at_exit { logout } unless logged_in? @imap end alias :conn :connection # Login to specified account. def login(*args) raise NotImplementedError, "The `#{self.class.name}#login` method is not implemented." end alias :sign_in :login # This version of login will raise error on failure... def login! login(true) end alias :sign_in! :login! # Returns +true+ when you are logged in to specified account. def logged_in? !!@logged_in end alias :signed_in? :logged_in? # Logout from GMail service. def logout @imap && logged_in? and @imap.logout ensure @logged_in = false end alias :sign_out :logout # Return labels object, which helps you with managing your GMail labels. # See Gmail::Labels for details. def labels @labels ||= Labels.new(conn) end # Compose new e-mail. # # ==== Examples # # mail = gmail.compose # mail.from "test@gmail.org" # mail.to "friend@gmail.com" # # ... or block style: # # mail = gmail.compose do # from "test@gmail.org" # to "friend@gmail.com" # subject "Hello!" # body "Hello my friend! long time..." # end # # Now you can deliver your mail: # # gmail.deliver(mail) def compose(mail=nil, &block) if block_given? mail = Mail.new(&block) elsif !mail mail = Mail.new end mail.delivery_method(*smtp_settings) mail.from = username unless mail.from mail end alias :message :compose # Compose (optionaly) and send given email. # # ==== Examples # # gmail.deliver do # to "friend@gmail.com" # subject "Hello friend!" # body "Hi! How are you?" # end # # ... or with already created message: # # mail = Mail.new { ... } # gmail.deliver(mail) # # mail = gmail.compose { ... } # gmail.deliver(mail) def deliver(mail=nil, raise_errors=false, &block) mail = compose(mail, &block) if block_given? mail.deliver! rescue Object => ex raise_errors and raise DeliveryError, "Couldn't deliver email: #{ex.to_s}" end # This version of deliver will raise error on failure... def deliver!(mail=nil, &block) deliver(mail, true, &block) end # Do something with given mailbox or within it context. # # ==== Examples # # mailbox = gmail.mailbox("INBOX") # mailbox.emails(:all) # mailbox.count(:unread, :before => Time.now-(20*24*3600)) # # ... or block style: # # gmail.label("Work") do |mailbox| # mailbox.emails(:unread) # mailbox.count(:all) # ... # end def mailbox(name, &block) @mailbox_mutex.synchronize do name = name.to_s mailbox = (mailboxes[name] ||= Mailbox.new(self, name)) switch_to_mailbox(name) if @current_mailbox != name if block_given? mailbox_stack << @current_mailbox result = block.arity == 1 ? block.call(mailbox) : block.call mailbox_stack.pop switch_to_mailbox(mailbox_stack.last) return result end return mailbox end end alias :in_mailbox :mailbox alias :in_label :mailbox alias :label :mailbox # Alias for mailbox("INBOX"). See Gmail::Client#mailbox # for details. def inbox mailbox("INBOX") end def mailboxes @mailboxes ||= {} end def inspect "#" end def fill_username(username) username =~ /@/ ? username : "#{username}@gmail.com" end def mail_domain username.split('@').last end private def switch_to_mailbox(mailbox) if mailbox mailbox = Net::IMAP.encode_utf7(mailbox) conn.select(mailbox) end @current_mailbox = mailbox end def mailbox_stack @mailbox_stack ||= [] end def smtp_settings [:smtp, { :address => GMAIL_SMTP_HOST, :port => GMAIL_SMTP_PORT, :domain => mail_domain, :user_name => username, :password => password, :authentication => 'plain', :enable_starttls_auto => true }] end end # Base end # Client end # Gmail