module Gmail class Message PREFETCH_ATTRS = ["UID", "ENVELOPE", "BODY.PEEK[]", "FLAGS", "X-GM-LABELS", "X-GM-MSGID", "X-GM-THRID"].freeze # Raised when given label doesn't exists. class NoLabelError < RuntimeError; end def initialize(mailbox, uid, _attrs = nil) @uid = uid @mailbox = mailbox @gmail = mailbox.instance_variable_get("@gmail") if mailbox # UGLY @_attrs = _attrs end def uid @uid ||= fetch("UID") end def msg_id @msg_id ||= fetch("X-GM-MSGID") end alias_method :message_id, :msg_id def thr_id @thr_id ||= fetch("X-GM-THRID") end alias_method :thread_id, :thr_id def envelope @envelope ||= fetch("ENVELOPE") end def message @message ||= Mail.new(fetch("BODY[]")) end alias_method :raw_message, :message def flags @flags ||= fetch("FLAGS") end def labels @labels ||= fetch("X-GM-LABELS") end # Mark message with given flag. def flag(name) !!@gmail.mailbox(@mailbox.name) do @gmail.conn.uid_store(uid, "+FLAGS", [name]) clear_cached_attributes end end # Unmark message. def unflag(name) !!@gmail.mailbox(@mailbox.name) do @gmail.conn.uid_store(uid, "-FLAGS", [name]) clear_cached_attributes end end # Do commonly used operations on message. def mark(flag) case flag when :read then read! when :unread then unread! when :deleted then delete! when :spam then spam! else flag(flag) end end # Check whether message is read def read? flags.include?(:Seen) end # Mark as read. def read! flag(:Seen) end # Mark as unread. def unread! unflag(:Seen) end # Check whether message is starred def starred? flags.include?(:Flagged) end # Mark message with star. def star! flag(:Flagged) end # Remove message from list of starred. def unstar! unflag(:Flagged) end # Marking as spam is done by adding the `\Spam` label. To undo this, # you just re-apply the `\Inbox` label (see `#unspam!`) def spam! add_label("\\Spam") end # Deleting is done by adding the `\Trash` label. To undo this, # you just re-apply the `\Inbox` label (see `#undelete!`) def delete! add_label("\\Trash") end # Archiving is done by adding the `\All Mail` label. To undo this, # you just re-apply the `\Inbox` label (see `#unarchive!`) # # IMAP's fetch('1:100', (X-GM-LABELS)) function does not fetch inbox, just emails labeled important? # http://stackoverflow.com/a/28973760 # In my testing the currently selected mailbox is always excluded from the X-GM-LABELS results. # When you called conn.select() it implicitly selected 'INBOX', therefore excluding 'Inbox' # from the list of labels. # If you selected a different mailbox then you would see '\\\\Inbox' in your results: def archive! @gmail.find(message.message_id).remove_label('\Inbox') end def unarchive! @gmail.find(message.message_id).add_label('\Inbox') end alias_method :unspam!, :unarchive! alias_method :undelete!, :unarchive! def move_to(name, from = nil) add_label(name) @gmail.find(message.message_id).remove_label(from) if from end alias_method :move, :move_to alias_method :move!, :move_to alias_method :move_to!, :move_to # Use Gmail IMAP Extensions to add a Label to an email def add_label(name) @gmail.mailbox(@mailbox.name) do @gmail.conn.uid_store(uid, "+X-GM-LABELS", [Net::IMAP.encode_utf7(name.to_s)]) clear_cached_attributes end end alias_method :label, :add_label alias_method :label!, :add_label alias_method :add_label!, :add_label # Use Gmail IMAP Extensions to remove a Label from an email def remove_label(name) @gmail.mailbox(@mailbox.name) do @gmail.conn.uid_store(uid, "-X-GM-LABELS", [Net::IMAP.encode_utf7(name.to_s)]) clear_cached_attributes end end alias_method :remove_label!, :remove_label def inspect "#