From f7a6a136af932e18ea6ce3685a5689ffae121208 Mon Sep 17 00:00:00 2001 From: Adimir Colen Date: Mon, 30 Aug 2010 11:28:20 -0300 Subject: [PATCH 01/11] `gem_original_require': no such file to load -- mime/message (LoadError) http://stackoverflow.com/questions/2954789/installing-the-ruby-gmail-rubygem-on-mac-os-snow-leopard --- lib/gmail/message.rb | 1 - 1 file changed, 1 deletion(-) diff --git a/lib/gmail/message.rb b/lib/gmail/message.rb index d23ceeb..1cbcbbe 100644 --- a/lib/gmail/message.rb +++ b/lib/gmail/message.rb @@ -1,4 +1,3 @@ -require 'mime/message' class Gmail class Message def initialize(gmail, mailbox, uid) From 1fe1509ac3b58575e5cbd793b9fe4bde9cf1a8ab Mon Sep 17 00:00:00 2001 From: Dominik Elberskirch Date: Sun, 7 Nov 2010 18:02:10 +0100 Subject: [PATCH 02/11] Fixed ArgumentErrors --- lib/gmail.rb | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/lib/gmail.rb b/lib/gmail.rb index 851356d..52e2ccc 100644 --- a/lib/gmail.rb +++ b/lib/gmail.rb @@ -50,7 +50,7 @@ def labels # gmail.label(name) def label(name) - mailboxes[name] ||= Mailbox.new(self, mailbox) + mailboxes[name] ||= Mailbox.new(self, name) end alias :mailbox :label @@ -119,7 +119,7 @@ def in_mailbox(mailbox, &block) end return value else - mailboxes[name] ||= Mailbox.new(self, mailbox) + mailboxes[mailbox] ||= Mailbox.new(self, mailbox) end end alias :in_label :in_mailbox From 35656b3bda7eb80b4e9a511ca06a72a4ddd871eb Mon Sep 17 00:00:00 2001 From: Dominik Elberskirch Date: Sun, 7 Nov 2010 18:04:28 +0100 Subject: [PATCH 03/11] Fixed missing dependency of mime gem, pushed Version --- Rakefile | 1 + VERSION | 2 +- ruby-gmail.gemspec | 11 +++++++---- 3 files changed, 9 insertions(+), 5 deletions(-) diff --git a/Rakefile b/Rakefile index 7ef1da8..c7d8252 100644 --- a/Rakefile +++ b/Rakefile @@ -14,6 +14,7 @@ begin 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" gem.add_dependency('shared-mime-info', '>= 0') gem.add_dependency('mail', '>= 2.2.1') + gem.add_dependency('mime', '>= 0.1') # gem is a Gem::Specification... see http://www.rubygems.org/read/chapter/20 for additional settings end Jeweler::GemcutterTasks.new diff --git a/VERSION b/VERSION index 0ea3a94..ee1372d 100644 --- a/VERSION +++ b/VERSION @@ -1 +1 @@ -0.2.0 +0.2.2 diff --git a/ruby-gmail.gemspec b/ruby-gmail.gemspec index 2a88686..a428319 100644 --- a/ruby-gmail.gemspec +++ b/ruby-gmail.gemspec @@ -5,11 +5,11 @@ Gem::Specification.new do |s| s.name = %q{ruby-gmail} - s.version = "0.2.0" + s.version = "0.2.2" s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version= s.authors = ["BehindLogic"] - s.date = %q{2010-05-14} + s.date = %q{2010-11-07} 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.} s.email = %q{gems@behindlogic.com} s.extra_rdoc_files = [ @@ -39,7 +39,7 @@ Support me in making new and better gems: http://pledgie.com/campaign } s.rdoc_options = ["--charset=UTF-8"] s.require_paths = ["lib"] - s.rubygems_version = %q{1.3.6} + s.rubygems_version = %q{1.3.7} s.summary = %q{A Rubyesque interface to Gmail, with all the tools you'll need.} s.test_files = [ "test/test_gmail.rb", @@ -50,16 +50,19 @@ Support me in making new and better gems: http://pledgie.com/campaign current_version = Gem::Specification::CURRENT_SPECIFICATION_VERSION s.specification_version = 3 - if Gem::Version.new(Gem::RubyGemsVersion) >= Gem::Version.new('1.2.0') then + if Gem::Version.new(Gem::VERSION) >= Gem::Version.new('1.2.0') then s.add_runtime_dependency(%q, [">= 0"]) s.add_runtime_dependency(%q, [">= 2.2.1"]) + s.add_runtime_dependency(%q, [">= 0.1"]) else s.add_dependency(%q, [">= 0"]) s.add_dependency(%q, [">= 2.2.1"]) + s.add_dependency(%q, [">= 0.1"]) end else s.add_dependency(%q, [">= 0"]) s.add_dependency(%q, [">= 2.2.1"]) + s.add_dependency(%q, [">= 0.1"]) end end From f5f73f9f381e4bdc412f28bcfc193c9b450ab075 Mon Sep 17 00:00:00 2001 From: Geoff Youngs Date: Tue, 30 Nov 2010 18:17:56 +0000 Subject: [PATCH 04/11] Fix typos --- lib/gmail.rb | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/lib/gmail.rb b/lib/gmail.rb index 851356d..52e2ccc 100644 --- a/lib/gmail.rb +++ b/lib/gmail.rb @@ -50,7 +50,7 @@ def labels # gmail.label(name) def label(name) - mailboxes[name] ||= Mailbox.new(self, mailbox) + mailboxes[name] ||= Mailbox.new(self, name) end alias :mailbox :label @@ -119,7 +119,7 @@ def in_mailbox(mailbox, &block) end return value else - mailboxes[name] ||= Mailbox.new(self, mailbox) + mailboxes[mailbox] ||= Mailbox.new(self, mailbox) end end alias :in_label :in_mailbox From 73c05431cf26dc2860f92d5245e4e933d8f80923 Mon Sep 17 00:00:00 2001 From: Geoff Youngs Date: Tue, 30 Nov 2010 18:19:26 +0000 Subject: [PATCH 05/11] Add more advanced label functions and searching. In GMail - Fix #labels on non-gmail accounts - stop assuming that the "[Gmail]" hierachy exists - Add #imap_xlist - Monkey patches XLIST support into Net::IMAP if it's missing. - Caches result until a new label is created - Add #inbox_label, #allmail_label, #spam_label, #trash_label, #drafts_label, #important_label, #starred_label - Uses XLIST to identify function of standard folders - Add #inbox, #allmail, #spam, #trash, #drafts, #important, #starred, #sent - Short cuts to known mailboxes - Add #normal_labels - Returns list of "normal" labels - ie. not sent, etc. - Add #label_of_type(type) - Looks up known mailbox In GMail::Mailbox - In #emails - Add support for additional all IMAP search keywords via hash params to #emails(). - Throw runtime error for unknown keys In GMail::Message - Add #message_id - UIDs are different for the same message across different folders, so Message-ID header is the test for uniqueness - Add #has_label?(name) - Indicates whether message has given label applied - Add #archived?, #starred?, #sent?, #important? - Shortcuts to check whether the message has been archived, starred etc. - Add #labels - returns list of labels applied to message - Search all known folders for messages with this message-id - Add #remove_label(label) - deletes message from given mailbox/label - ie. delete message from named folder --- lib/gmail.rb | 91 ++++++++++++++++++++++++++++++++++++++++---- lib/gmail/mailbox.rb | 76 +++++++++++++++++++++++++++++++++--- lib/gmail/message.rb | 66 ++++++++++++++++++++++++++++++-- 3 files changed, 217 insertions(+), 16 deletions(-) diff --git a/lib/gmail.rb b/lib/gmail.rb index 52e2ccc..7e966c4 100644 --- a/lib/gmail.rb +++ b/lib/gmail.rb @@ -33,19 +33,96 @@ class << self # gmail.label('News') # ########################### - - def inbox - in_label('inbox') - end - def create_label(name) + @xlist_result = nil imap.create(name) end # List the available labels def labels - (imap.list("", "%") + imap.list("[Gmail]/", "%")).inject([]) { |labels,label| - label[:name].each_line { |l| labels << l }; labels } + labels = [] + prefixes = [''] + done = [] + until prefixes.empty? + prefix = prefixes.shift + done << prefix + (imap.list(prefix, "%")||[]).each { |e| + if e[:attr].include?(:Haschildren) + unless done.include?(e[:name]+"/") or e[:name].empty? + prefixes << e[:name]+"/" + end + end + unless e[:attr].include?(:Noselect) + labels << e[:name] + end + } + end + labels + end + + def imap_xlist + unless @imap.respond_to?(:xlist) + def @imap.xlist(refname, mailbox) + handler = proc do |resp| + if resp.kind_of?(Net::IMAP::UntaggedResponse) and resp.name == "XLIST" && resp.raw_data.nil? + list_resp = Net::IMAP::ResponseParser.new.instance_eval { + @str, @pos, @token = "#{resp.name} " + resp.data, 0, nil + @lex_state = Net::IMAP::ResponseParser::EXPR_BEG + list_response + } + if @responses['XLIST'].last == resp.data + @responses['XLIST'].pop + @responses['XLIST'].push(list_resp.data) + end + end + end + synchronize do + add_response_handler(handler) + send_command('XLIST', '', '*') + remove_response_handler(handler) + return @responses.delete('XLIST') + end + end + end + + @xlist_result ||= @imap.xlist('', '*') + end + + def self.special_labels + [:Inbox, :Allmail, :Spam, :Trash, :Drafts, :Important, :Starred, :Sent] + end + + def special_labels + self.class.special_labels + end + + def normal_labels + imap_xlist.reject { |label| + label.attr.include?(:Noselect) or label.attr.any? { |flag| special_labels.include?(flag) } + }.map { |label| + label.name + } + end + + def imap_xlist! + @xlist_result = nil + imap_xlist + end + + def label_of_type(type) + info = imap_xlist.find { |l| l.attr.include?(type) } + info && info.name || nil + end + + special_labels.each do |label| + module_eval <<-EOL + def #{label.to_s.downcase} &block + in_label(#{label.to_s.downcase}_label, &block) + end + def #{label.to_s.downcase}_label + label_of_type(#{label.inspect}) + end + EOL end # gmail.label(name) diff --git a/lib/gmail/mailbox.rb b/lib/gmail/mailbox.rb index de3b760..678d840 100644 --- a/lib/gmail/mailbox.rb +++ b/lib/gmail/mailbox.rb @@ -23,6 +23,39 @@ def to_s name end + FLAG_KEYWORDS = [ + ['ANSWERED', 'UNANSWERED'], + ['DELETED', 'UNDELETED'], + ['DRAFT', 'UNDRAFT'], + ['FLAGGED', 'UNFLAGGED'], + ['RECENT', 'OLD'], + ['SEEN', 'UNSEEN'] + ] + VALID_SEARCH_KEYS = %w[ + ALL + BCC + BEFORE + BODY + CC + FROM + HEADER + KEYWORD + LARGER + NEW + NOT + ON + OR + SENTBEFORE + SENTON + SENTSINCE + SINCE + SMALLER + SUBJECT + TEXT + TO + UID + UNKEYWORD + ] + FLAG_KEYWORDS.flatten # Method: emails # Args: [ :all | :unread | :read ] # Opts: {:since => Date.new} @@ -45,11 +78,44 @@ def emails(key_or_opts = :all, opts={}) if !opts.empty? # Support for several search macros # :before => Date, :on => Date, :since => Date, :from => String, :to => String - search.concat ['SINCE', opts[:after].to_imap_date] if opts[:after] - search.concat ['BEFORE', opts[:before].to_imap_date] if opts[:before] - search.concat ['ON', opts[:on].to_imap_date] if opts[:on] - search.concat ['FROM', opts[:from]] if opts[:from] - search.concat ['TO', opts[:to]] if opts[:to] + opts = opts.dup + VALID_SEARCH_KEYS.each do |keyword| + key = keyword.downcase.intern + if opts[key] + val = opts.delete(key) + case val + when Date, Time + search.concat([keyword, val.to_imap_date]) + when String + search.concat([keyword, val]) + when Numeric + search.concat([keyword, val.to_s]) + when Array + search.concat([keyword, *val]) + when TrueClass, FalseClass + # If it's a known flag keyword & val == false, + # try to invert it's meaning. + if row = FLAG_KEYWORDS.find { |row| row.include?(keyword) } + row_index = row.index(keyword) + altkey = row[ val ? row_index : 1 - row_index ] + search.push(altkey) + else + search.push(keyword) if val + end + when NilClass + next + else + search.push(keyword) # e.g. flag + end + end + end + + # API compatibility + search.concat ['SINCE', opts.delete(:after).to_imap_date] if opts[:after] + + unless opts.empty? + raise "Unrecognised keys: #{opts.keys.inspect}" + end end # puts "Gathering #{(aliases[key] || key).inspect} messages for mailbox '#{name}'..." diff --git a/lib/gmail/message.rb b/lib/gmail/message.rb index d23ceeb..a1131c0 100644 --- a/lib/gmail/message.rb +++ b/lib/gmail/message.rb @@ -29,6 +29,48 @@ def unflag(flg) end ? true : false end + def message_id + @message_id ||= self.header['Message-ID'].value + end + + def has_label?(label) + return true if @mailbox == @gmail.mailbox(label) + @gmail.in_mailbox(@gmail.mailbox(label)) do |mailbox| + search = ['HEADER', 'Message-ID', self.message_id] + res = @gmail.imap.uid_search(search) + if res && !res.empty? + return true + end + end + false + end + + def archived? + ! has_label?(@gmail.inbox_label) + end + + def starred? + has_label?(@gmail.starred_label) + end + + def sent? + has_label?(@gmail.sent_label) + end + + def important? + has_label?(@gmail.important_label) + end + + def labels + mbox = @mailbox + list = [mbox.name] + @gmail.normal_labels.each do |label| + next if mbox.name == label + list << label if has_label?(label) + end + list + end + # Gmail Operations def mark(flag) case flag @@ -39,7 +81,7 @@ def mark(flag) when :deleted flag(:Deleted) when :spam - move_to('[Gmail]/Spam') + move_to(@gmail.spam_label) end ? true : false end @@ -72,15 +114,31 @@ def label!(name) # We're not sure of any 'labels' except the 'mailbox' we're in at the moment. # Research whether we can find flags that tell which other labels this email is a part of. - # def remove_label(name) - # end + def remove_label(label) + return false if label.downcase == @gmail.allmail_label.downcase + + return delete! if label.downcase == @mailbox.name.downcase + + @gmail.in_mailbox(@gmail.label(label)) do |mailbox| + message = mailbox.emails(['HEADER', 'Message-ID', self.message_id]).first + if message + message.delete! + else + # Doesn't have label in the first place? + end + end + end def move_to(name) label(name) && delete! end def archive! - move_to('[Gmail]/All Mail') + move_to(@gmail.allmail_label) + end + + def save_attachments_to(path=nil) + attachments.each {|a| a.save_to_file(path) } end private From 96e4f6c0849c5fb16ecf9565cfacafe196085736 Mon Sep 17 00:00:00 2001 From: Geoff Youngs Date: Wed, 1 Dec 2010 12:29:25 +0000 Subject: [PATCH 06/11] Fix re-fetching of message body for every attribute request --- lib/gmail/message.rb | 1 + 1 file changed, 1 insertion(+) diff --git a/lib/gmail/message.rb b/lib/gmail/message.rb index a1131c0..7d8bdc5 100644 --- a/lib/gmail/message.rb +++ b/lib/gmail/message.rb @@ -145,6 +145,7 @@ def save_attachments_to(path=nil) # Parsed MIME message object def message + return @message if @message require 'mail' _body = @gmail.in_mailbox(@mailbox) { @gmail.imap.uid_fetch(uid, "RFC822")[0].attr["RFC822"] } @message ||= Mail.new(_body) From 7ee56e82c4c5951b3a6123963794e0fc8f7d44a7 Mon Sep 17 00:00:00 2001 From: Geoff Youngs Date: Wed, 1 Dec 2010 12:30:03 +0000 Subject: [PATCH 07/11] Add support for pre-fetching the messages returned by search In Gmail::Mailbox - Add support for :fetch key in #emails() to indicate the message bodies should be fetched In Gmail::Mail - Add #loaded? to check whether message has already been downloaded - Add #set_body(body) to set the contents of a message --- lib/gmail/mailbox.rb | 18 ++++++++++++++++-- lib/gmail/message.rb | 10 +++++++++- 2 files changed, 25 insertions(+), 3 deletions(-) diff --git a/lib/gmail/mailbox.rb b/lib/gmail/mailbox.rb index 678d840..bb443ce 100644 --- a/lib/gmail/mailbox.rb +++ b/lib/gmail/mailbox.rb @@ -75,6 +75,9 @@ def emails(key_or_opts = :all, opts={}) else 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." end + + fetch = opts.delete(:fetch) + if !opts.empty? # Support for several search macros # :before => Date, :on => Date, :since => Date, :from => String, :to => String @@ -118,10 +121,21 @@ def emails(key_or_opts = :all, opts={}) end end - # puts "Gathering #{(aliases[key] || key).inspect} messages for mailbox '#{name}'..." + list = [] + @gmail.in_mailbox(self) do - @gmail.imap.uid_search(search).collect { |uid| messages[uid] ||= Message.new(@gmail, self, uid) } + uids = @gmail.imap.uid_search(search) + list = uids.collect { |uid| messages[uid] ||= Message.new(@gmail, self, uid) } + if fetch + missing = list.reject { |message| message.loaded? }.map { |message| message.uid } + @gmail.imap.uid_fetch(missing, 'RFC822').each do |info| + message = messages[info.attr['UID']] + message.set_body(info.attr['RFC822']) + end + end end + + list end # This is a convenience method that really probably shouldn't need to exist, but it does make code more readable diff --git a/lib/gmail/message.rb b/lib/gmail/message.rb index 7d8bdc5..9ada775 100644 --- a/lib/gmail/message.rb +++ b/lib/gmail/message.rb @@ -141,8 +141,16 @@ def save_attachments_to(path=nil) attachments.each {|a| a.save_to_file(path) } end - private + def loaded? + !! @message + end + def set_body(body) + require 'mail' + @message = Mail.new(body) + end + + private # Parsed MIME message object def message return @message if @message From 5ca0d69748a682ac59cc717fd095c96a16e93772 Mon Sep 17 00:00:00 2001 From: Adimir Colen Date: Wed, 1 Dec 2010 12:34:46 -0200 Subject: [PATCH 08/11] Version bump to 0.2.3 --- VERSION | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/VERSION b/VERSION index ee1372d..373f8c6 100644 --- a/VERSION +++ b/VERSION @@ -1 +1 @@ -0.2.2 +0.2.3 \ No newline at end of file From 767d0aa4d86caba66b6e067284ac83134a751fdc Mon Sep 17 00:00:00 2001 From: Geoff Youngs Date: Thu, 2 Dec 2010 19:44:15 +0000 Subject: [PATCH 09/11] Rename #special_labels to #gmail_label_types --- lib/gmail.rb | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/lib/gmail.rb b/lib/gmail.rb index 7e966c4..279a4f6 100644 --- a/lib/gmail.rb +++ b/lib/gmail.rb @@ -88,17 +88,17 @@ def @imap.xlist(refname, mailbox) @xlist_result ||= @imap.xlist('', '*') end - def self.special_labels + def self.gmail_label_types [:Inbox, :Allmail, :Spam, :Trash, :Drafts, :Important, :Starred, :Sent] end - def special_labels - self.class.special_labels + def gmail_label_types + self.class.gmail_label_types end def normal_labels imap_xlist.reject { |label| - label.attr.include?(:Noselect) or label.attr.any? { |flag| special_labels.include?(flag) } + label.attr.include?(:Noselect) or label.attr.any? { |flag| gmail_label_types.include?(flag) } }.map { |label| label.name } @@ -114,7 +114,7 @@ def label_of_type(type) info && info.name || nil end - special_labels.each do |label| + gmail_label_types.each do |label| module_eval <<-EOL def #{label.to_s.downcase} &block in_label(#{label.to_s.downcase}_label, &block) From 9a912eed7e837a75e27e166af5126475a7ca878d Mon Sep 17 00:00:00 2001 From: Geoff Youngs Date: Thu, 2 Dec 2010 19:45:24 +0000 Subject: [PATCH 10/11] Add ability to filter search results GMail::Message - Add #envelope to store/read back imap envelope contents - Add #message_id? to check whether we know the message id yet - Add #subject, #from, #to to read values from envelope with body fallback GMail::Mailbox - Change behaviour - always fetch IMAP ENVELOPE for search results unless we have already loaded message - Add GMail::Mailbox::MessageList - array like class for search results - Add MessageList#with_label(label) - filter results - Searches label folder for messages in MessageList --- lib/gmail/mailbox.rb | 65 ++++++++++++++++++++++++++++++++++++++++++-- lib/gmail/message.rb | 19 ++++++++++++- 2 files changed, 81 insertions(+), 3 deletions(-) diff --git a/lib/gmail/mailbox.rb b/lib/gmail/mailbox.rb index bb443ce..1e8baf7 100644 --- a/lib/gmail/mailbox.rb +++ b/lib/gmail/mailbox.rb @@ -126,18 +126,79 @@ def emails(key_or_opts = :all, opts={}) @gmail.in_mailbox(self) do uids = @gmail.imap.uid_search(search) list = uids.collect { |uid| messages[uid] ||= Message.new(@gmail, self, uid) } + if fetch missing = list.reject { |message| message.loaded? }.map { |message| message.uid } - @gmail.imap.uid_fetch(missing, 'RFC822').each do |info| + @gmail.imap.uid_fetch(missing, ['ENVELOPE', 'RFC822']).each do |info| message = messages[info.attr['UID']] + message.envelope = info.attr['ENVELOPE'] message.set_body(info.attr['RFC822']) end + else + missing = list.reject { |message| message.message_id? }.map { |message| message.uid } + @gmail.imap.uid_fetch(missing, ['ENVELOPE']).each do |info| + message = messages[info.attr['UID']] + message.envelope = info.attr['ENVELOPE'] + message.message_id = info.attr['ENVELOPE'].message_id + end end end - list + MessageList.new(@gmail, list) end + class MessageList + include Enumerable + attr_reader :list + def initialize(gmail, list) + @gmail = gmail + @list = list + end + def size + @list.size + end + def each(&block) + @list.each(&block) + end + def with_label(label) + label = label.is_a?(String) ? @gmail.label(label) : label + @gmail.in_label(label) do |mbox| + + # Search for message ids in named folder + search = [] + @list.each_with_index do |m, index| + search.unshift "OR" unless index.zero?#.empty? + search << "HEADER" << "Message-ID" << m.message_id + end + uids = @gmail.imap.uid_search(search) + + # Fetch envelopes for uids + message_ids = [] + + missing_uids = uids.collect { |uid| + mbox.messages[uid] ||= Message.new(@gmail, mbox, uid) + }.reject { |message| + if message.loaded? or message.message_id? + message_ids << message.message_id + true + else + false + end + }.map { |message| + message.uid + } + + message_ids += @gmail.imap.uid_fetch(missing_uids, ['ENVELOPE']).map do |info| + message = mbox.messages[info.attr['UID']] + message.envelope ||= info.attr['ENVELOPE'] + info.attr['ENVELOPE'].message_id + end + + MessageList.new(@gmail, @list.select { |m| message_ids.include?(m.message_id) }) + end + end + end + # This is a convenience method that really probably shouldn't need to exist, but it does make code more readable # if seriously all you want is the count of messages. def count(*args) diff --git a/lib/gmail/message.rb b/lib/gmail/message.rb index 9ada775..971b8f2 100644 --- a/lib/gmail/message.rb +++ b/lib/gmail/message.rb @@ -29,8 +29,25 @@ def unflag(flg) end ? true : false end + attr_writer :message_id + attr_writer :envelope + def message_id? + !! (@envelope || @message_id || @message) + end def message_id - @message_id ||= self.header['Message-ID'].value + @message_id ||= @envelope ? @envelope.message_id : self.header['Message-ID'].value + end + def envelope + @envelope ||= @gmail.in_mailbox(@mailbox) { @gmail.imap.uid_fetch(uid, "ENVELOPE")[0].attr["ENVELOPE"] } + end + def subject + @envelope ? @envelope.subject : self.header['Subject'].value + end + def from + @envelope ? @envelope.from : self.header['From'].value + end + def to + @envelope ? @envelope.to : self.header['To'].value end def has_label?(label) From 0950d5552aeabb2213d0a4ea063e60b219a87f6d Mon Sep 17 00:00:00 2001 From: Geoff Youngs Date: Thu, 2 Dec 2010 20:05:32 +0000 Subject: [PATCH 11/11] Make GMail::Message#archive! behave more GMail like --- lib/gmail/message.rb | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/lib/gmail/message.rb b/lib/gmail/message.rb index 971b8f2..7707f6c 100644 --- a/lib/gmail/message.rb +++ b/lib/gmail/message.rb @@ -129,8 +129,6 @@ def label!(name) end end - # We're not sure of any 'labels' except the 'mailbox' we're in at the moment. - # Research whether we can find flags that tell which other labels this email is a part of. def remove_label(label) return false if label.downcase == @gmail.allmail_label.downcase @@ -150,8 +148,10 @@ def move_to(name) label(name) && delete! end + # Archive, in the gmail sense, means remove label Inbox, + # rather than simply remove current label def archive! - move_to(@gmail.allmail_label) + remove_label(@gmail.inbox_label) end def save_attachments_to(path=nil)