├── .bundle
└── config
├── .gitignore
├── .travis.yml
├── CHANGELOG.md
├── Gemfile
├── LICENSE
├── README.md
├── Rakefile
├── TODO.md
├── account.yml.example
├── gmail.gemspec
├── lib
├── gmail.rb
└── gmail
│ ├── api_resource.rb
│ ├── base
│ ├── create.rb
│ ├── delete.rb
│ ├── get.rb
│ ├── list.rb
│ ├── modify.rb
│ ├── trash.rb
│ └── update.rb
│ ├── draft.rb
│ ├── gmail_object.rb
│ ├── label.rb
│ ├── message.rb
│ ├── thread.rb
│ ├── util.rb
│ └── version.rb
└── test
├── gmail
├── api_resource_test.rb
├── draft_test.rb
├── gmail_object_test.rb
├── label_test.rb
├── message_test.rb
├── thread_test.rb
└── util_test.rb
├── test_data.rb
└── test_helper.rb
/.bundle/config:
--------------------------------------------------------------------------------
1 | --- {}
2 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | ## MAC OS
2 | .DS_Store
3 |
4 | ## TEXTMATE
5 | *.tmproj
6 | tmtags
7 |
8 | ## EMACS
9 | *~
10 | \#*
11 | .\#*
12 |
13 | ## VIM
14 | *.swp
15 |
16 | ## rubymine
17 | .idea
18 |
19 | ## PROJECT::GENERAL
20 | coverage
21 | rdoc
22 | pkg
23 | Gemfile.lock
24 |
25 | ## Gem build
26 | *.gem
27 |
28 | ## PROJECT::SPECIFIC
29 | *.rdb
30 |
31 | ## Test Account details
32 | account.yml
33 |
--------------------------------------------------------------------------------
/.travis.yml:
--------------------------------------------------------------------------------
1 | language: ruby
2 | rvm:
3 | - 1.9.3
4 | - 2.2.0
5 | - 2.0.0
6 | - 2.1.0
7 | - 2.1.2
--------------------------------------------------------------------------------
/CHANGELOG.md:
--------------------------------------------------------------------------------
1 | # gmail-api-ruby gem changelog
2 | ## 0.0.1 / 2015-01
3 |
4 | * Birthday!
5 |
6 | ## 0.0.3 / 2015-01-15
7 |
8 | * forward_with, reply_sender_with and reply_all_with won't trigger a deliver but will build the ready to send object
9 |
10 | ## 0.0.4 / 2015-01-15
11 |
12 | * No change, only gem description
13 |
14 | ## 0.0.5 / 2015-01-15
15 |
16 | * updated dependencies
17 |
18 | ## 0.0.6 / 2015-01-16
19 |
20 | * Added insert method for Message and some minor improvements
21 |
22 | ## 0.0.7 / 2015-01-19
23 |
24 | * Fix array empty errors for listing method
25 |
26 | ## 0.0.8 / 2015-01-29
27 |
28 | * minor fix
29 |
30 | ## 0.0.9 / 2015-02-12
31 |
32 | * minor fix
33 |
34 | ## 0.0.10 / 2015-02-17
35 |
36 | * Fixed email parsing in forward and reply method when contact names contain ,
37 |
38 | ## 0.0.11 / 2015-06-22
39 |
40 | * Forked to Carpela. Changed auth to work with Service Account
41 |
--------------------------------------------------------------------------------
/Gemfile:
--------------------------------------------------------------------------------
1 | source "http://rubygems.org"
2 |
3 | gemspec
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | Copyrignt (c) 2015 Julien Hobeika
2 |
3 | Permission is hereby granted, free of charge, to any person obtaining
4 | a copy of this software and associated documentation files (the
5 | "Software"), to deal in the Software without restriction, including
6 | without limitation the rights to use, copy, modify, merge, publish,
7 | distribute, sublicense, and/or sell copies of the Software, and to
8 | permit persons to whom the Software is furnished to do so, subject to
9 | the following conditions:
10 |
11 | The above copyright notice and this permission notice shall be
12 | included in all copies or substantial portions of the Software.
13 |
14 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
15 | EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
16 | MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
17 | NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
18 | LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
19 | OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
20 | WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
21 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # Gmail for Ruby
2 |
3 | A Ruby interface to Gmail API: Search,
4 | read and send multipart emails, archive, mark as read/unread, delete emails,
5 | and manage labels. Everything goes through Gmail API (and not through IMAP or SMTP protocols)
6 |
7 | [](http://badge.fury.io/rb/gmail-api-ruby)
8 | [](https://travis-ci.org/jhk753/gmail-ruby-api)
9 | [](https://gemnasium.com/jhk753/gmail-ruby-api)
10 |
11 |
12 | # Notice
13 |
14 | If for your usecase, the gem is too limited there are two solutions for you:
15 |
16 | 1. Contribute ;)
17 | 2. Look at [Gmail Api doc](https://developers.google.com/gmail/api/v1/reference) to:
18 | * Do custom query by adding parameters I didn't talk about in my doc
19 | * If for some reason I forgot to build some methods, note that you can call fully custom request via Gmail.client (Standard Google Api Client)
20 |
21 | # To Do
22 |
23 | * write proper error handling
24 |
25 | ## Installation
26 |
27 | gem install gmail-api-ruby
28 |
29 | ## Initialization
30 |
31 | ```ruby
32 | Gmail.client_id = "...Your app client id..." or the email from your service account credentials
33 | Gmail.client_secret = "...Your app Secret..." or the pem version of hte api key for service account
34 | Gmail.refresh_token = "...the refresh token of the Gmail account you want to use..." or the account email address for service account auth
35 | # Or for service Accounts
36 | Gmail.auth_method = "service_account"
37 | Gmail.client_id = "... or the email from your service account credentials..."
38 | Gmail.client_secret = "...pem version of the api key ..."
39 | Gmail.email_account = "...the email account you're going to use"
40 | Gmail.auth_scopes = ['http://mail.google.com'] # an array of the permissions required.
41 | ```
42 |
43 | ## Usage
44 |
45 | ```ruby
46 | require "gmail"
47 | ```
48 |
49 | ### Common methods
50 |
51 | this works for Messages, Labels, Drafts and Threads (everything)
52 |
53 | ```ruby
54 | Gmail::Message.all
55 | Gmail::Message.all(maxResults: -1) #will parse everything. Use with care. Can through request timeout if used in web apps
56 | Gmail::Message.get(message_id)
57 | some_gmail_message.delete
58 | ```
59 |
60 | this will work for Messages and Threads
61 |
62 | ```ruby
63 | some_message.archive
64 | some_message.unarchive
65 | some_message.trash
66 | some_message.untrash
67 | some_message.star
68 | some_message.unstar
69 | some_message.mark_as_read
70 | some_message.mark_as_unread
71 |
72 | Gmail::Message.search(in: "labelId" from: "me@gmail.com", to: "you@gmail.com, theothers@gmail.com", subject: "some subject", after: "date", before: "date", has_words: "some words", has_not_words: "some text")
73 | Gmail::Message.search("some words") #search as you would do in gmail interface
74 |
75 | ```
76 |
77 |
78 | ### Message
79 |
80 | Create a Message object
81 |
82 | ```ruby
83 | m = Gmail::Message.new(
84 | from: "test@test.com",
85 | to: "hello@world.com",
86 | subject: "this is the subject",
87 | body: "this is a text body")
88 | ```
89 |
90 | If you want a multipart message
91 |
92 | ```ruby
93 | m = Gmail::Message.new(
94 | from: "test@test.com",
95 | to: "hello@world.com",
96 | subject: "this is the subject",
97 | text: "this is a text body",
98 | html: "
this is a html body
",
99 | labelIds: ["cool label", "Newsletter"] #labelIds is always array of labels
100 | )
101 | ```
102 |
103 | From this you can create a Draft in Gmail
104 |
105 | ```ruby
106 | m.create_draft
107 | ```
108 |
109 | or send the Message
110 |
111 | ```ruby
112 | m.deliver
113 | ```
114 |
115 | or simply insert the message in the user mailbox
116 |
117 | ```ruby
118 | m.insert
119 | ```
120 |
121 | Notice that the Message object can use from, to, cc, bcc, threadId, labelIds, text, html, body
122 |
123 | If you need to send Message or create draft with custom headers or set other headers.
124 | Or if you need to create a different multipart email, you need to build the "raw" email yourself
125 |
126 | example:
127 |
128 | ```ruby
129 | mail = Mail.new #this is the native ruby Mail object
130 | #
131 | # construct your Mail object
132 | #
133 | raw = Base64.urlsafe_encode64 mail.to_s
134 | m = Gmail::Message.new(raw: raw)
135 | ```
136 |
137 | In that scenario, you still assign, if needed, ThreadId and labelIds as previously
138 |
139 | ```ruby
140 | m.threadId = "somethreadId"
141 | m.labelIds = ["cool label"]
142 | ```
143 |
144 | If you want to quickly generate a reply or a forward to message
145 |
146 | ```ruby
147 | # this will construct everything for you, keeping the subject the thread etc as it would happen in Gmail
148 | # reply only to the sender of Message m.
149 | msg = m.reply_sender_with Gmail::Message.new(body: "some reply text")
150 | # reply to all (sender, to (without yourself) and cc)
151 | msg = m.reply_all_with Gmail::Message.new(body: "some reply text")
152 | # forward
153 | msg = m.forward_with Gmail::Message.new(body: "some forward text", to: "address@toforward.com")
154 | # Note that the above will not send the resulting msg
155 | msg.deliver #to send the constructed reply message
156 |
157 | ```
158 |
159 | Other stuffs that you can do with Message object
160 |
161 | ```ruby
162 | m.detailed #if for any reason Google did send us the full detail of on email object
163 | m.thread #to get the associated Thread
164 | m.inbox? #to know if email is in inbox
165 | m.sent? #to know if email is a sent email
166 | m.unread? #to know if email is unread
167 | ```
168 |
169 | Those are basics helpers feel free to add more if you want (ex: starred?, important?, etc)
170 |
171 |
172 | ## Thread
173 |
174 | Get a thread
175 |
176 | ```ruby
177 | one_thread = Gmail::Thread.get(thread_id)
178 | ```
179 |
180 | or
181 |
182 | ```ruby
183 | one_thread = one_message.thread
184 | ```
185 |
186 | Filter messages in Thread
187 |
188 | ```ruby
189 | one_thread.unread_messages
190 | one_thread.sent_messages
191 | ```
192 |
193 | Expand messages in Thread
194 |
195 | ```ruby
196 | one_thread.detailed #this will return a thread object but with all messages detailed
197 | one_thread.messages #this will return an array of message objects
198 | ```
199 |
200 | ## Draft
201 |
202 | As we explained in Message, you create a draft with
203 |
204 | ```ruby
205 | d = some_message.create_draft
206 | ```
207 |
208 | Modify it with
209 |
210 | ```ruby
211 | d.message.subject = "some different subject than before"
212 | d.save
213 | ```
214 |
215 | send it with
216 |
217 | ```ruby
218 | d.deliver
219 | ```
220 |
221 | ## Label
222 |
223 | You can create a label like this:
224 |
225 | ```ruby
226 | l = Gmail::Label.new
227 | l.name = "different Name"
228 | l.messageListVisibility = "hide" #can be 'hide' or 'show'
229 | l.labelListVisibility = "labelShowIfUnread" #can be "labelShowIfUnread", "labelShow", "labelHide"
230 | l.save
231 | ```
232 |
233 | You can modify a label like this:
234 |
235 | ```ruby
236 | l = Gmail::Label.get("labelId")
237 | l.name = "different Name"
238 | l.messageListVisibility = "hide"
239 | l.labelListVisibility = "labelShowIfUnread"
240 | l.save
241 | ```
242 |
243 | You can use Labels to directly access box information
244 |
245 | ```ruby
246 | l.detailed #will display number of messages and number of threads if you don't see it
247 | ```
248 |
249 | For system labels like inbox, sent, trash, important, starred, draft, spam, unread, category_updates, category_promotions, category_social, category_personal, category_forums
250 |
251 | ```ruby
252 | l = Gmail::Label.inbox
253 | ```
254 |
255 | Access threads and messages from labels
256 |
257 | ```ruby
258 | l.threads
259 | l.messages
260 |
261 | l.unread_threads
262 | l.unread_messages
263 | ```
264 |
265 | Access threads, drafts and messages with labels
266 |
267 | ```ruby
268 | Gmail::Message.all(labelIds: ["UNREAD", "INBOX"])
269 | ```
270 |
271 | ## License
272 |
273 | Copyrignt (c) 2015 Julien Hobeika
274 |
275 | Permission is hereby granted, free of charge, to any person obtaining
276 | a copy of this software and associated documentation files (the
277 | "Software"), to deal in the Software without restriction, including
278 | without limitation the rights to use, copy, modify, merge, publish,
279 | distribute, sublicense, and/or sell copies of the Software, and to
280 | permit persons to whom the Software is furnished to do so, subject to
281 | the following conditions:
282 |
283 | The above copyright notice and this permission notice shall be
284 | included in all copies or substantial portions of the Software.
285 |
286 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
287 | EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
288 | MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
289 | NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
290 | LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
291 | OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
292 | WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
--------------------------------------------------------------------------------
/Rakefile:
--------------------------------------------------------------------------------
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 API 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 | require 'rake/testtask'
27 |
28 | task :default => [:test]
29 |
30 | Rake::TestTask.new do |t|
31 | t.pattern = './test/**/*_test.rb'
32 | end
--------------------------------------------------------------------------------
/TODO.md:
--------------------------------------------------------------------------------
1 | # TODO
2 |
3 | *proper errors handling
--------------------------------------------------------------------------------
/account.yml.example:
--------------------------------------------------------------------------------
1 | # Auth Method
2 | google_api_auth_method: ENV['GOOGLE_API_AUTH_METHOD']
3 |
4 | #App Info
5 | application_name: ENV['APP_NAME']
6 | application_version: ENV['APP_VERSION']
7 |
8 | # Web Application Auth
9 | client_id: ENV['GOOGLE_API_CLIENT_ID']
10 | client_secret: ENV['GOOGLE_API_CLIENT_SECRET']
11 | refresh_token: ENV['GOOGLE_API_REFRESH_TOKEN']
12 |
13 | # Service Account Auth
14 | google_api_key: ENV['GOOGLE_API_KEY']
15 | google_api_email: ENV['GOOGLE_API_EMAIL']
16 | email_account: ENV['GOOGLE_ACCOUNT']
17 | auth_scopes: ENV['GOOGLE_AUTH_SCOPES']
--------------------------------------------------------------------------------
/gmail.gemspec:
--------------------------------------------------------------------------------
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-api-ruby"
8 | s.summary = "A Ruby interface to Gmail API (NO IMAP, NO SMTP), with all the tools you will need."
9 | s.description = "A Ruby interface to Gmail API (NO IMAP, NO SMTP).
10 | Search, read and send multipart emails; archive, mark as read/unread,
11 | delete emails; and manage labels. Everything is done through the Gmail API without going through IMAP or SMTP Protocol
12 | "
13 | s.version = Gmail::VERSION
14 | s.platform = Gem::Platform::RUBY
15 | s.authors = ["Julien Hobeika","Keiran Betteley"]
16 | s.homepage = "http://github.com/jhk753/gmail-ruby-api"
17 | s.licenses = ['MIT']
18 |
19 | # runtime dependencies
20 | s.required_ruby_version = '>= 1.9.3'
21 | s.add_dependency "mime", ">= 0.1"
22 | s.add_dependency "mail", ">= 2.2.1"
23 | s.add_dependency "activesupport"
24 | s.add_dependency 'google-api-client', "0.8.6"
25 | s.add_dependency "hooks", ">=0.4.0"
26 | s.add_dependency "hashie", ">=3.3.2"
27 | s.add_dependency "stringex"
28 |
29 | # development dependencies
30 | s.add_development_dependency "rake"
31 | s.add_development_dependency "test-unit"
32 | s.add_development_dependency('mocha', '~> 1.0.0')
33 | s.add_development_dependency('shoulda', '~> 3.5.0')
34 |
35 |
36 | s.add_development_dependency "gem-release"
37 |
38 | s.files = `git ls-files`.split("\n")
39 | s.test_files = `git ls-files -- {test,spec,features}/*`.split("\n")
40 | s.executables = `git ls-files -- bin/*`.split("\n").map{ |f| File.basename(f) }
41 | s.require_paths = ["lib"]
42 | end
43 |
--------------------------------------------------------------------------------
/lib/gmail.rb:
--------------------------------------------------------------------------------
1 | require 'mail'
2 | require 'hashie'
3 | require 'hooks'
4 | require 'google/api_client'
5 | require 'gmail/gmail_object'
6 | require 'gmail/api_resource'
7 | #base
8 | require 'gmail/base/create'
9 | require 'gmail/base/delete'
10 | require 'gmail/base/get'
11 | require 'gmail/base/list'
12 | require 'gmail/base/update'
13 | require 'gmail/base/modify'
14 | require 'gmail/base/trash'
15 |
16 | #object
17 | require 'gmail/util'
18 | require 'gmail/message'
19 | require 'gmail/draft'
20 | require 'gmail/thread'
21 | require 'gmail/label'
22 |
23 | module Gmail
24 |
25 | class << self
26 | attr_accessor :auth_method, :client_id, :client_secret,
27 | :refresh_token, :auth_scopes, :email_account, :application_name, :application_version
28 | attr_reader :service, :client, :mailbox_email
29 | def new hash
30 | [:auth_method, :client_id, :client_secret, :refresh_token, :auth_scopes, :email_account, :application_name, :application_version].each do |accessor|
31 | Gmail.send("#{accessor}=", hash[accessor.to_s])
32 | end
33 | end
34 | end
35 |
36 | Google::APIClient.logger.level = 3
37 | @service = Google::APIClient.new.discovered_api('gmail', 'v1')
38 | Google::APIClient.logger.level = 2
39 |
40 | begin
41 | Gmail.new YAML.load_file("account.yml") # for development purpose
42 | rescue
43 |
44 | end
45 |
46 | def self.request(method, params={}, body={}, auth_method=@auth_method)
47 |
48 | params[:userId] ||= "me"
49 | case auth_method
50 | when "web_application"
51 | if @client.nil?
52 | self.connect
53 | end
54 | when "service_account"
55 | if @client.nil?
56 | self.service_account_connect
57 | elsif self.client.authorization.principal != @email_account
58 | self.service_account_connect
59 | end
60 | end
61 |
62 | if body.empty?
63 | response = @client.execute(
64 | :api_method => method,
65 | :parameters => params,
66 |
67 | :headers => {'Content-Type' => 'application/json'})
68 | else
69 |
70 | response = @client.execute(
71 | :api_method => method,
72 | :parameters => params,
73 | :body_object => body,
74 | :headers => {'Content-Type' => 'application/json'})
75 | end
76 | parse(response)
77 |
78 | end
79 |
80 | def self.mailbox_email
81 | @mailbox_email ||= self.request(@service.users.to_h['gmail.users.getProfile'])[:emailAddress]
82 | end
83 |
84 |
85 |
86 | def self.connect(client_id=@client_id, client_secret=@client_secret, refresh_token=@refresh_token)
87 | unless client_id
88 | raise 'No client_id specified'
89 | end
90 |
91 | unless client_secret
92 | raise 'No client_secret specified'
93 | end
94 |
95 | unless refresh_token
96 | raise 'No refresh_token specified'
97 | end
98 |
99 | @client = Google::APIClient.new(
100 | application_name: @application_name,
101 | application_version: @application_version
102 | )
103 | @client.authorization.client_id = client_id
104 | @client.authorization.client_secret = client_secret
105 | @client.authorization.refresh_token = refresh_token
106 | @client.authorization.grant_type = 'refresh_token'
107 | @client.authorization.fetch_access_token!
108 | @client.auto_refresh_token = true
109 |
110 | #@service = @client.discovered_api('gmail', 'v1')
111 |
112 | end
113 |
114 | def self.service_account_connect(
115 | client_id=@client_id, client_secret=@client_secret,
116 | email_account=@email_account, auth_scopes=@auth_scopes,
117 | application_name=@application_name, application_version=@application_version
118 | )
119 | puts "Authenticating service account - #{email_account}"
120 |
121 |
122 | @client = Google::APIClient.new(application_name: application_name, application_version: application_version)
123 |
124 |
125 |
126 | key = Google::APIClient::KeyUtils.load_from_pem(
127 | client_secret,
128 | 'notasecret')
129 | asserter = Google::APIClient::JWTAsserter.new(
130 | client_id,
131 | auth_scopes,
132 | key
133 | )
134 | @client.authorization = asserter.authorize(email_account)
135 |
136 | end
137 |
138 | def self.parse(response)
139 | begin
140 |
141 | if response.body.empty?
142 | return response.body
143 | else
144 | response = JSON.parse(response.body)
145 | end
146 |
147 | rescue JSON::ParserError
148 | raise "error code: #{response.error},body: #{response.body})"
149 | end
150 |
151 | r = Gmail::Util.symbolize_names(response)
152 | if r[:error]
153 | raise "#{r[:error]}"
154 | end
155 | r
156 | end
157 |
158 |
159 | end # Gmail
160 |
--------------------------------------------------------------------------------
/lib/gmail/api_resource.rb:
--------------------------------------------------------------------------------
1 | module Gmail
2 | class APIResource < GmailObject
3 | def self.class_name
4 | self.name.split('::')[-1]
5 | end
6 |
7 | def self.base_method
8 | Gmail.service.users.send("#{class_name.downcase}s")
9 | end
10 |
11 | end
12 | end
--------------------------------------------------------------------------------
/lib/gmail/base/create.rb:
--------------------------------------------------------------------------------
1 | module Gmail
2 | module Base
3 | module Create
4 | module ClassMethods
5 | def create(body, opts={})
6 | response = Gmail.request(base_method.send("create"), {}, body)
7 | Util.convert_to_gmail_object(response, class_name.downcase)
8 | end
9 | end
10 |
11 | def self.included(base)
12 | base.extend(ClassMethods)
13 | end
14 | end
15 | end
16 | end
--------------------------------------------------------------------------------
/lib/gmail/base/delete.rb:
--------------------------------------------------------------------------------
1 | module Gmail
2 | module Base
3 | module Delete
4 | def delete(opts={})
5 | response = Gmail.request(self.class.base_method.send("delete"),{id: id})
6 | if response == ""
7 | true
8 | else
9 | false
10 | end
11 | end
12 |
13 | module ClassMethods
14 | def delete(id, opts={})
15 | response = Gmail.request(base_method.send("delete"),{id: id})
16 | if response == ""
17 | true
18 | else
19 | false
20 | end
21 | end
22 | end
23 |
24 | def self.included(base)
25 | base.extend(ClassMethods)
26 | end
27 |
28 |
29 | end
30 | end
31 | end
--------------------------------------------------------------------------------
/lib/gmail/base/get.rb:
--------------------------------------------------------------------------------
1 | module Gmail
2 | module Base
3 | module Get
4 | module ClassMethods
5 | def get(id)
6 | response = Gmail.request(base_method.send("get"), {id: id})
7 | Util.convert_to_gmail_object(response, class_name.downcase)
8 |
9 | end
10 | end
11 |
12 | def self.included(base)
13 | base.extend(ClassMethods)
14 | end
15 | end
16 | end
17 | end
--------------------------------------------------------------------------------
/lib/gmail/base/list.rb:
--------------------------------------------------------------------------------
1 | module Gmail
2 | module Base
3 | module List
4 | module ClassMethods
5 | def all(filters={}, opts={})
6 | max_results = filters[:maxResults] || 100
7 | opts[:items] ||= []
8 |
9 | if max_results == -1
10 | filters.merge!({maxResults: 100})
11 | end
12 | response = Gmail.request(base_method.send("list"), filters)
13 | items = response["#{class_name.downcase}s".to_sym] || []
14 | next_page_token = response[:nextPageToken]
15 | opts[:items] = opts[:items] + items
16 |
17 | if items.count < 100 || items.count < max_results
18 | Util.convert_to_gmail_object(opts[:items], class_name.downcase)
19 | else
20 | max_results = (max_results == -1)?-1:max_results-items.count
21 | all(filters.merge({maxResults: max_results, pageToken: next_page_token}), opts)
22 | end
23 | end
24 |
25 | def search(q={})
26 | if q.is_a? String
27 | all({q: q})
28 | else
29 | query = ""
30 | [:from, :to, :subject].each do |prop|
31 | query += "#{prop.to_s}:(#{q[prop].downcase}) " unless q[prop].nil?
32 | q.delete(prop)
33 | end
34 | [:in, :before, :after].each do |prop|
35 | query += "#{prop.to_s}:#{q[prop]} " unless q[prop].nil?
36 | q.delete(prop)
37 | end
38 |
39 | query += "#{q[:has_words]} " unless q[:has_words].nil?
40 | query += "-{#{q[:has_not_words]}}" unless q[:has_not_words].nil?
41 | q.delete(:has_words)
42 | q.delete(:has_not_words)
43 |
44 | all(q.merge({q: query}))
45 | end
46 | end
47 | end
48 |
49 | def self.included(base)
50 | base.extend(ClassMethods)
51 | end
52 | end
53 | end
54 | end
--------------------------------------------------------------------------------
/lib/gmail/base/modify.rb:
--------------------------------------------------------------------------------
1 | module Gmail
2 | module Base
3 | module Modify
4 | def modify!(addLabelIds=[], removeLabelIds=[])
5 | response = Gmail.request(self.class.base_method.send("modify"),{id: id}, {addLabelIds: addLabelIds, removeLabelIds: removeLabelIds})
6 | d = Util.convert_to_gmail_object(response, self.class.class_name.downcase)
7 | @values = d.values
8 | self
9 | end
10 |
11 | def modify(addLabelIds=[], removeLabelIds=[])
12 | response = Gmail.request(self.class.base_method.send("modify"),{id: id}, {addLabelIds: addLabelIds, removeLabelIds: removeLabelIds})
13 | d = Util.convert_to_gmail_object(response, self.class.class_name.downcase)
14 | end
15 |
16 | def archive
17 | modify([], ["INBOX"])
18 | end
19 |
20 | def archive!
21 | modify!([], ["INBOX"])
22 | end
23 |
24 | def unarchive
25 | modify(["INBOX"], [] )
26 | end
27 |
28 | def unarchive!
29 | modify!(["INBOX"], [] )
30 | end
31 |
32 | def star
33 | modify(["STARRED"], [] )
34 | end
35 |
36 | def star!
37 | modify!(["STARRED"], [] )
38 | end
39 |
40 | def unstar
41 | modify([],["STARRED"] )
42 | end
43 |
44 | def unstar!
45 | modify!([],["STARRED"] )
46 | end
47 |
48 | def mark_as_read
49 | modify([],["UNREAD"] )
50 | end
51 |
52 | def mark_as_read!
53 | modify!([],["UNREAD"] )
54 | end
55 |
56 | def mark_as_unread
57 | modify(["UNREAD"],[] )
58 | end
59 |
60 | def mark_as_unread!
61 | modify!(["UNREAD"],[] )
62 | end
63 |
64 | end
65 | end
66 | end
--------------------------------------------------------------------------------
/lib/gmail/base/trash.rb:
--------------------------------------------------------------------------------
1 | module Gmail
2 | module Base
3 | module Trash
4 | def trash(opts={})
5 | response = Gmail.request(self.class.base_method.send("trash"),{id: id})
6 | Util.convert_to_gmail_object(response, self.class.class_name.downcase)
7 | end
8 |
9 | def untrash(opts={})
10 | response = Gmail.request(self.class.base_method.send("untrash"),{id: id})
11 | Util.convert_to_gmail_object(response, self.class.class_name.downcase)
12 | end
13 |
14 | module ClassMethods
15 | def trash(id, opts={})
16 | response = Gmail.request(base_method.send("trash"),{id: id})
17 | Util.convert_to_gmail_object(response, class_name.downcase)
18 | end
19 |
20 | def untrash(id, opts={})
21 | response = Gmail.request(base_method.send("untrash"),{id: id})
22 | Util.convert_to_gmail_object(response, class_name.downcase)
23 | end
24 | end
25 |
26 | def self.included(base)
27 | base.extend(ClassMethods)
28 | end
29 |
30 |
31 | end
32 | end
33 | end
--------------------------------------------------------------------------------
/lib/gmail/base/update.rb:
--------------------------------------------------------------------------------
1 | module Gmail
2 | module Base
3 | module Update
4 | def update!(body)
5 | if id.nil?
6 | d = self.class.create(body)
7 | else
8 | response = Gmail.request(self.class.base_method.send("update"),{id: id}, body)
9 | d = Util.convert_to_gmail_object(response, self.class.class_name.downcase)
10 | end
11 | @values = d.values
12 | self
13 | end
14 |
15 | def update(body)
16 | if id.nil?
17 | d = self.class.create(body)
18 | else
19 | response = Gmail.request(self.class.base_method.send("update"),{id: id}, body)
20 | d = Util.convert_to_gmail_object(response, self.class.class_name.downcase)
21 | end
22 | d
23 | end
24 | end
25 | end
26 | end
--------------------------------------------------------------------------------
/lib/gmail/draft.rb:
--------------------------------------------------------------------------------
1 | module Gmail
2 | class Draft < APIResource
3 | include Base::List
4 | include Base::Create
5 | include Base::Delete
6 | include Base::Get
7 | include Base::Update
8 |
9 | def message
10 | if @values.message.is_a?(Message)
11 | @values.message
12 | else
13 | @values.message = Util.convert_to_gmail_object(to_hash[:message], key="message")
14 | if @values.message.payload.nil?
15 | self.detailed!
16 | message
17 | end
18 | @values.message
19 | end
20 | end
21 |
22 | def save(opts={})
23 | msg = {raw: message.raw}
24 | if message.threadId
25 | msg[:threadId] = message.threadId
26 | end
27 | if message.labelIds
28 | msg[:labelIds] = message.labelIds
29 | end
30 | body = {message: msg}
31 | update(body)
32 | end
33 |
34 | def save!(opts={})
35 | msg = {raw: message.raw}
36 | if message.threadId
37 | msg[:threadId] = message.threadId
38 | end
39 | if message.labelIds
40 | msg[:labelIds] = message.labelIds
41 | end
42 | body = {message: msg}
43 | update!(body)
44 | end
45 |
46 | def deliver
47 | response = Gmail.request(self.class.base_method.to_h['gmail.users.drafts.send'],{},{id: id})
48 | Message.get(response[:id])
49 | end
50 |
51 |
52 |
53 | end
54 | end
--------------------------------------------------------------------------------
/lib/gmail/gmail_object.rb:
--------------------------------------------------------------------------------
1 | module Gmail
2 | class GmailObject
3 | include Enumerable
4 | include Hooks
5 | define_hooks :after_initialize
6 |
7 | # The default :id method is deprecated and isn't useful to us
8 | if method_defined?(:id)
9 | undef :id
10 | end
11 |
12 | def initialize(hash={})
13 | @values = Hashie::Mash.new hash
14 | run_hook :after_initialize
15 | end
16 |
17 |
18 | def to_s(*args)
19 | JSON.pretty_generate(@values.to_hash)
20 | end
21 |
22 | def inspect
23 | "#<#{self.class}:0x#{self.object_id.to_s(16)}> " + to_s
24 | end
25 |
26 | def [](k)
27 | @values[k.to_sym]
28 | end
29 |
30 | def []=(k, v)
31 | @values.send("#{k}=", v)
32 | end
33 |
34 | def to_json(*a)
35 | JSON.generate(@values)
36 | end
37 |
38 | def as_json(*a)
39 | @values.as_json(*a)
40 | end
41 |
42 | def detailed
43 | if self.class == GmailObject
44 | raise "Can't detail a generic GmailObject. It needs to be a Thread, Message, Draft or Label"
45 | end
46 |
47 | self.class.get(id)
48 | end
49 |
50 | def refresh
51 | if self.class == GmailObject
52 | raise "Can't refresh a generic GmailObject. It needs to be a Thread, Message, Draft or Label"
53 | end
54 | @values = self.class.get(id).values
55 | self
56 | end
57 |
58 | alias_method :detailed!, :refresh
59 | #
60 | def to_hash
61 | Util.symbolize_names(@values.to_hash)
62 | end
63 |
64 | def values
65 | @values
66 | end
67 | #
68 | # def each(&blk)
69 | # @values.each(&blk)
70 | # end
71 | #
72 | # def _dump(level)
73 | # Marshal.dump([@values, @api_key])
74 | # end
75 | #
76 | # def self._load(args)
77 | # values, api_key = Marshal.load(args)
78 | # construct_from(values)
79 | # end
80 | #
81 | # if RUBY_VERSION < '1.9.2'
82 | # def respond_to?(symbol)
83 | # @values.has_key?(symbol) || super
84 | # end
85 | # end
86 | #
87 | protected
88 |
89 | def metaclass
90 | class << self; self; end
91 | end
92 | #
93 | # def remove_accessors(keys)
94 | # metaclass.instance_eval do
95 | # keys.each do |k|
96 | # next if @@permanent_attributes.include?(k)
97 | # k_eq = :"#{k}="
98 | # remove_method(k) if method_defined?(k)
99 | # remove_method(k_eq) if method_defined?(k_eq)
100 | # end
101 | # end
102 | # end
103 | #
104 | # def add_accessors(keys)
105 | # metaclass.instance_eval do
106 | # keys.each do |k|
107 | # next if @@permanent_attributes.include?(k)
108 | # k_eq = :"#{k}="
109 | # define_method(k) { @values[k] }
110 | # define_method(k_eq) do |v|
111 | # if v == ""
112 | # raise ArgumentError.new(
113 | # "You cannot set #{k} to an empty string." +
114 | # "We interpret empty strings as nil in requests." +
115 | # "You may set #{self}.#{k} = nil to delete the property.")
116 | # end
117 | # @values[k] = v
118 | # @unsaved_values.add(k)
119 | # end
120 | # end
121 | # end
122 | # end
123 | #
124 | def method_missing(name, *args)
125 |
126 | if @values.send(name.to_s + "?")
127 | @values.send(name)
128 | else
129 | begin
130 | @values.send(name.to_s, args[0])
131 | rescue
132 | begin
133 | super.send(name)
134 | rescue
135 | nil
136 | end
137 | end
138 | end
139 | end
140 |
141 |
142 | #
143 | # def respond_to_missing?(symbol, include_private = false)
144 | # super
145 | # end
146 | end
147 | end
--------------------------------------------------------------------------------
/lib/gmail/label.rb:
--------------------------------------------------------------------------------
1 | module Gmail
2 | class Label < APIResource
3 | include Base::List
4 | include Base::Create
5 | include Base::Delete
6 | include Base::Get
7 | include Base::Update
8 |
9 | def save
10 | update(to_hash)
11 | end
12 |
13 | def save!
14 | update!(to_hash)
15 | end
16 |
17 | def self.boxes
18 | @boxes ||= [:inbox, :sent, :trash, :important, :starred, :draft, :spam, :unread, :category_updates, :category_promotions, :category_social, :category_personal, :category_forums ]
19 | end
20 |
21 | boxes.each do |method|
22 | define_singleton_method method do
23 | Label.get(method.to_s.upcase)
24 | end
25 | end
26 |
27 | def messages filters={}
28 | filters = {labelIds: [id]}.merge(filters)
29 | filters[:labelIds] = filters[:labelIds] | [id]
30 | Message.all(filters)
31 | end
32 |
33 | def unread_messages
34 | if messagesUnread == 0
35 | []
36 | else
37 | Message.all({labelIds: [id, "UNREAD"]})
38 | end
39 | end
40 |
41 | def threads filters={}
42 | filters = {labelIds: [id]}.merge(filters)
43 | filters[:labelIds] = filters[:labelIds] | [id]
44 | Thread.all(filters)
45 | end
46 |
47 | def unread_threads
48 | Thread.all({labelIds: [id, "UNREAD"]})
49 | end
50 |
51 | end
52 | end # Gmail
53 |
--------------------------------------------------------------------------------
/lib/gmail/message.rb:
--------------------------------------------------------------------------------
1 | # encoding: utf-8
2 | module Gmail
3 | class Message < APIResource
4 | include Base::List
5 | include Base::Delete
6 | include Base::Get
7 | include Base::Modify
8 | include Base::Trash
9 |
10 | require "stringex"
11 |
12 | after_initialize :set_basics
13 |
14 | def thread
15 | Thread.get(threadId)
16 | end
17 |
18 | def create_draft
19 | Draft.create(message: msg_parameters)
20 | end
21 |
22 | def deliver!
23 | response = Gmail.request(self.class.base_method.to_h['gmail.users.messages.send'],{}, msg_parameters)
24 | @values = Message.get(response[:id]).values
25 | self
26 | end
27 |
28 | def deliver
29 | response = Gmail.request(self.class.base_method.to_h['gmail.users.messages.send'],{}, msg_parameters)
30 | Message.get(response[:id])
31 | end
32 |
33 | def insert
34 | response = Gmail.request(self.class.base_method.insert,{}, msg_parameters)
35 | Message.get(response[:id])
36 | end
37 |
38 | def insert!
39 | response = Gmail.request(self.class.base_method.insert,{}, msg_parameters)
40 | @values = Message.get(response[:id]).values
41 | self
42 | end
43 |
44 | def reply_all_with msg
45 | msg = set_headers_for_reply msg
46 | msg = quote_in msg
47 | msg
48 | end
49 |
50 | def reply_sender_with msg
51 | msg = set_headers_for_reply msg
52 | msg = quote_in msg
53 | msg.cc = nil
54 | msg
55 | end
56 |
57 | def forward_with msg
58 | # save headers that need to be override by users compared to a classic reply
59 | x_cc = msg.cc
60 | x_to = msg.to
61 | x_bcc = msg.bcc
62 | x_subject = msg.subject || subject #if user doesn't override keep classic behavior
63 | # set headers as for reply
64 | msg = set_headers_for_reply msg
65 | # quote message
66 | msg = quote_in msg
67 | # reset saved overridden headers
68 | msg.cc = x_cc
69 | msg.to = x_to
70 | msg.bcc = x_bcc
71 | msg.subject = x_subject
72 | msg
73 | end
74 |
75 |
76 | def thread_id
77 | threadId
78 | end
79 |
80 |
81 | def unread?
82 | (labelIds||[]).include?("UNREAD")
83 | end
84 |
85 | def sent?
86 | (labelIds||[]).include?("SENT")
87 | end
88 |
89 | def inbox?
90 | (labelIds||[]).include?("INBOX")
91 | end
92 |
93 |
94 |
95 | def raw # is not in private because the method is used in Draft
96 | if super #check if raw is set to allow fully custom message to be sent
97 | super
98 | else
99 | s = self
100 | msg = Mail.new
101 | msg.subject = subject
102 | if body
103 | msg.body = body
104 | end
105 | msg.from = from
106 | msg.to = to
107 | msg.cc = cc
108 | msg.header['X-Bcc'] = bcc unless bcc.nil?#because Mail gem doesn't allow bcc headers...
109 | msg.in_reply_to = in_reply_to unless in_reply_to.nil?
110 | msg.references = references unless references.nil?
111 | if text || html
112 | bodypart = Mail::Part.new
113 | if text
114 | bodypart.text_part = Mail::Part.new do |p|
115 | content_type 'text/plain; charset=UTF-8'
116 | p.body s.text
117 | end
118 | end
119 | if html
120 | bodypart.html_part = Mail::Part.new do |p|
121 | content_type 'text/html; charset=UTF-8'
122 | p.body s.html
123 | end
124 | end
125 | msg.add_part bodypart
126 | end
127 | if attachments
128 | if attachments.is_a?(Hash)
129 | attachments.each do |name, attachment|
130 | msg.add_file filename: name, content: attachment
131 | end
132 | elsif attachments.is_a?(Array)
133 | attachments.each do |attachment|
134 | msg.add_file(attachment)
135 | end
136 | end
137 | end
138 | Base64.urlsafe_encode64 msg.to_s.sub("X-Bcc", "Bcc") #because Mail gem doesn't allow bcc headers...
139 | end
140 | end
141 |
142 | private
143 |
144 | def msg_parameters
145 | msg = {raw: raw}
146 | if threadId
147 | msg[:threadId] = threadId
148 | end
149 | if labelIds
150 | msg[:labelIds] = labelIds
151 | end
152 | msg
153 | end
154 |
155 | def self.find_addresses str
156 | Mail::AddressList.new("#{str}".to_ascii.gsub(/<(<(.)*@(.)*>)(.)*>/, '\1'))
157 | end
158 |
159 | def set_headers_for_reply msg
160 | #to_ar = []
161 | #split_regexp = Regexp.new("\s*,\s*")
162 | own_email = delivered_to || Gmail.mailbox_email
163 |
164 |
165 | to_ar = (Message.find_addresses(to).addresses + Message.find_addresses(cc).addresses).map(&:to_s)
166 | #to_ar = (to || "").split(split_regexp) + (cc || "").split(split_regexp)
167 | result = to_ar.grep(Regexp.new(own_email, "i"))
168 | to_ar = to_ar - result
169 |
170 | msg.subject = subject
171 | if from.match(Regexp.new(own_email, "i"))
172 | msg.to = to_ar.first
173 | to_ar = to_ar.drop(1)
174 | else
175 | msg.to = from
176 | end
177 | msg.cc = to_ar.join(", ")
178 | msg.bcc = nil
179 | msg.threadId = thread_id
180 | msg.references = ((references || "").split(Regexp.new "\s+") << message_id).join(" ")
181 | msg.in_reply_to = ((in_reply_to || "").split(Regexp.new "\s+") << message_id).join(" ")
182 | msg
183 | end
184 |
185 | def quote_in reply_msg
186 | text_to_append = "\r\n\r\n#{date} #{from}:\r\n\r\n>" + (body || text).gsub("\n", "\n>") unless body.nil? && text.nil?
187 | html_to_append = "\r\n
#{date} #{CGI.escapeHTML(from)}:
" + html + "
" unless html.nil?
188 | reply_msg.html = "" + reply_msg.html + "
" + html_to_append unless reply_msg.html.nil?
189 | reply_msg.text = reply_msg.text + text_to_append unless reply_msg.text.nil?
190 | reply_msg.body = reply_msg.body + text_to_append unless reply_msg.body.nil?
191 | reply_msg
192 | end
193 |
194 | def urlsafe_decode64 code
195 | Base64.urlsafe_decode64(code).force_encoding('UTF-8').encode
196 | end
197 |
198 |
199 | def set_basics
200 | if @values.payload
201 | ["From", "To", "Cc", "Subject", "Bcc", "Date", "Message-ID", "References", "In-Reply-To", "Delivered-To"].each do |n|
202 | if payload_n = @values.payload.headers.select{|h| h.name.downcase == n.downcase}.first
203 | @values.send(n.downcase.tr("-", "_") + "=", payload_n.value)
204 | end
205 | end
206 |
207 | if payload.parts
208 | content_payload = @values.payload.find_all_object_containing("mimeType", "multipart/alternative").first
209 | content_payload ||= @values.payload
210 | text_part=content_payload.find_all_object_containing("mimeType", "text/plain").first
211 | if text_part && text_part.body.data
212 | @values.text = urlsafe_decode64(text_part.body.data)
213 | end
214 | html_part=content_payload.find_all_object_containing("mimeType", "text/html").first
215 | if html_part && html_part.body.data
216 | @values.html = urlsafe_decode64(html_part.body.data)
217 | end
218 | end
219 | if payload.body.data
220 | @values.body = urlsafe_decode64(@values.payload.body.data)
221 | end
222 | end
223 | end
224 |
225 | class Hashie::Mash
226 | def find_all_object_containing(key, value )
227 | result=[]
228 | if self.send(key) == value
229 | result << self
230 | end
231 | self.values.each do |vs|
232 | vs = [vs] unless vs.is_a? Array
233 | vs.each do |v|
234 | result += v.find_all_object_containing(key,value) if v.is_a? Hashie::Mash
235 | end
236 | end
237 | result
238 | end
239 | end
240 |
241 | end
242 | end
--------------------------------------------------------------------------------
/lib/gmail/thread.rb:
--------------------------------------------------------------------------------
1 | module Gmail
2 | class Thread < APIResource
3 | include Base::List
4 | include Base::Delete
5 | include Base::Get
6 | include Base::Modify
7 | include Base::Trash
8 |
9 | def messages
10 |
11 | if @values.messages.is_a? Array
12 | if @values.messages.first.is_a? Message
13 | @values.messages
14 | else
15 | @values.messages = Util.convert_to_gmail_object(to_hash[:messages], key="message")
16 | end
17 | else
18 | self.detailed!
19 | messages
20 | end
21 |
22 | end
23 |
24 | def unread_messages
25 |
26 | messages.select{|m| m.unread?}
27 |
28 | end
29 |
30 |
31 | def sent_messages
32 |
33 | messages.select{|m| m.sent?}
34 |
35 | end
36 |
37 | end
38 | end
--------------------------------------------------------------------------------
/lib/gmail/util.rb:
--------------------------------------------------------------------------------
1 | module Gmail
2 | module Util
3 |
4 | def self.object_classes
5 | @object_classes ||= {
6 | # data structures
7 |
8 | # business objects
9 | 'draft' => Draft,
10 | 'label' => Label,
11 | 'message' => Message,
12 | 'thread' => Thread
13 | }
14 | end
15 |
16 | def self.convert_to_gmail_object(resp, key=nil)
17 | case resp
18 | when Array
19 | resp.map { |i| convert_to_gmail_object(i, key) }
20 | when Hash
21 | # Try converting to a known object class. If none available, fall back to generic StripeObject
22 | object_classes.fetch(key , GmailObject).new(resp)
23 | else
24 | resp
25 | end
26 | end
27 |
28 |
29 | def self.symbolize_names(object)
30 | case object
31 | when Hash
32 | new_hash = {}
33 | object.each do |key, value|
34 | key = (key.to_sym rescue key) || key
35 | new_hash[key] = symbolize_names(value)
36 | end
37 | new_hash
38 | when Array
39 | object.map { |value| symbolize_names(value) }
40 | else
41 | object
42 | end
43 | end
44 | end
45 | end
--------------------------------------------------------------------------------
/lib/gmail/version.rb:
--------------------------------------------------------------------------------
1 | module Gmail
2 | VERSION = "0.0.14"
3 | end # Gmail
4 |
--------------------------------------------------------------------------------
/test/gmail/api_resource_test.rb:
--------------------------------------------------------------------------------
1 | # -*- coding: utf-8 -*-
2 | require File.expand_path('../../test_helper', __FILE__)
3 |
4 | module Gmail
5 | class ApiResourceTest < Test::Unit::TestCase
6 |
7 | should "creating a new APIResource should not fetch over the network" do
8 | @mock.expects(:execute).never
9 | Gmail::Label.new({
10 | name: "test"
11 | })
12 | end
13 |
14 | should "setting an attribute should not cause a network request" do
15 | @mock.expects(:execute).never
16 | m = Gmail::Message.new({subject: "test"})
17 | m.body = "this is a test body"
18 | end
19 |
20 | should "accessing id should not issue a fetch" do
21 | @mock.expects(:execute).never
22 | c = Gmail::Message.new({subject: "test"})
23 | c.id
24 | end
25 |
26 | should "construct URL properly with base query parameters" do
27 | response = test_response(test_thread_list)
28 | @mock.expects(:execute).with(api_method: Gmail.service.users.threads.list, parameters: {userId: "me"}, headers: {'Content-Type' => 'application/json'}).returns(response)
29 | Gmail::Thread.all
30 |
31 | @mock.expects(:execute).with(api_method: Gmail.service.users.threads.list, parameters: {maxResults: 150, userId: "test@test.com"}, headers: {'Content-Type' => 'application/json'}).returns(response)
32 | Gmail::Thread.all(maxResults: 150, userId: "test@test.com")
33 | end
34 |
35 |
36 | should "deleting should return true" do
37 | @mock.expects(:execute).with(api_method: Gmail.service.users.drafts.delete, parameters: {userId: "me", id: test_draft[:id]}, headers: {'Content-Type' => 'application/json'}).once.returns(test_response(""))
38 |
39 | d = Gmail::Draft.new test_draft
40 |
41 | assert_equal true, d.delete
42 |
43 | end
44 |
45 |
46 | end
47 | end
--------------------------------------------------------------------------------
/test/gmail/draft_test.rb:
--------------------------------------------------------------------------------
1 | # -*- coding: utf-8 -*-
2 | require File.expand_path('../../test_helper', __FILE__)
3 |
4 | module Gmail
5 | class DraftTest < Test::Unit::TestCase
6 |
7 | should "Draft should be retrievable by id" do
8 |
9 | @mock.expects(:execute).with(api_method: Gmail.service.users.drafts.get, parameters: {userId: "me", id: test_draft[:id]}, headers: {'Content-Type' => 'application/json'}).once.returns(test_response(test_draft))
10 | d = Gmail::Draft.get(test_draft[:id])
11 | assert d.kind_of?Gmail::Draft
12 | assert_equal test_draft[:id], d.id
13 | end
14 |
15 | should "drafts should be listable" do
16 | @mock.expects(:execute).with(api_method: Gmail.service.users.drafts.list, parameters: {userId: "me"}, headers: {'Content-Type' => 'application/json'}).once.returns(test_response(test_draft_list))
17 | list = Gmail::Draft.all
18 | assert list.kind_of? Array
19 | assert list[0].kind_of? Gmail::Draft
20 | end
21 |
22 | context "Message Object in draft" do
23 | should "retrieved Draft should not generate call to get Message Object" do
24 | draft = Gmail::Draft.new(test_draft)
25 | @mock.expects(:execute).never
26 | assert draft.message.kind_of?Gmail::Message
27 | end
28 |
29 | should "Draft get from a draft list should generate call to get Message Object" do
30 | @mock.expects(:execute).with(api_method: Gmail.service.users.drafts.list, parameters: {userId: "me"}, headers: {'Content-Type' => 'application/json'}).once.returns(test_response(test_draft_list))
31 | list = Gmail::Draft.all
32 | draft = list.first
33 |
34 | @mock.expects(:execute).with(api_method: Gmail.service.users.drafts.get, parameters: {userId: "me", id: test_draft[:id]}, headers: {'Content-Type' => 'application/json'}).once.returns(test_response(test_draft))
35 |
36 | assert draft.message.kind_of?Gmail::Message
37 | assert_not_nil draft.message.payload
38 | end
39 | end
40 |
41 |
42 | should "drafts should be deletable" do
43 | @mock.expects(:execute).with(api_method: Gmail.service.users.drafts.delete, parameters: {userId: "me", id: test_draft[:id]}, headers: {'Content-Type' => 'application/json'}).once.returns(test_response(""))
44 | d = Gmail::Draft.new(test_draft)
45 | r = d.delete
46 | assert r
47 | end
48 |
49 | should "drafts should be updateable" do
50 | draft_hash = test_draft
51 | draft_hash[:message].merge!({labelIds: ["COOL LABEL"]})
52 | @mock.expects(:execute).with(api_method: Gmail.service.users.drafts.get, parameters: {id: test_draft[:id], userId: "me"} , headers: {'Content-Type' => 'application/json'}).once.returns(test_response(draft_hash))
53 |
54 | d = Gmail::Draft.new(id: test_draft[:id]).detailed
55 | # those two lines are required because raw generation change between two calls...
56 | raw = d.message.raw
57 | d.message.raw = raw
58 | ###
59 | assert_equal ["COOL LABEL"], d.message.labelIds
60 |
61 | draft_hash[:message].merge!({labelIds: ["INBOX"]})
62 |
63 | @mock.expects(:execute).with(api_method: Gmail.service.users.drafts.update, parameters: {id: test_draft[:id], userId: "me"}, body_object:{message: {raw: d.message.raw, threadId: test_draft[:message][:threadId], labelIds: ["INBOX"]}} , headers: {'Content-Type' => 'application/json'}).twice.returns(test_response(draft_hash))
64 |
65 |
66 | d.message.labelIds = ["INBOX"]
67 | new_d = d.save
68 | assert_equal ["INBOX"], new_d.message.labelIds
69 | assert_not_equal d.object_id, new_d.object_id
70 | new_d = d.save!
71 | assert_equal d.object_id, new_d.object_id
72 | end
73 |
74 | should "create should return a new Draft" do
75 | draft_hash = test_draft
76 | draft_hash.delete(:id)
77 | d = Gmail::Draft.new draft_hash
78 | # those two lines are required because raw generation change between two calls...
79 | raw = d.message.raw
80 | d.message.raw = raw
81 | ###
82 | @mock.expects(:execute).with(api_method: Gmail.service.users.drafts.create, parameters: {userId: "me"}, body_object:{message: {raw: d.message.raw, threadId: draft_hash[:message][:threadId], labelIds: draft_hash[:message][:labelIds]}} , headers: {'Content-Type' => 'application/json'}).once.returns(test_response(test_draft))
83 | created_d = d.save!
84 | assert_equal Gmail::Draft, created_d.class
85 | assert_equal test_draft[:id], d.id
86 | end
87 |
88 |
89 | should "Draft should be sendable and return a Message" do
90 | @mock.expects(:execute).with(api_method: Gmail.service.users.drafts.to_h['gmail.users.drafts.send'], parameters: {userId: "me"}, body_object:{id: test_draft[:id]} , headers: {'Content-Type' => 'application/json'}).once.returns(test_response(test_message))
91 | @mock.expects(:execute).with(api_method: Gmail.service.users.messages.get, parameters: {userId: "me", id: test_message[:id]}, headers: {'Content-Type' => 'application/json'}).once.returns(test_response(test_message))
92 |
93 | d = Gmail::Draft.new test_draft
94 | m = d.deliver
95 |
96 | assert m.kind_of?Gmail::Message
97 |
98 | end
99 |
100 |
101 |
102 |
103 | end
104 | end
--------------------------------------------------------------------------------
/test/gmail/gmail_object_test.rb:
--------------------------------------------------------------------------------
1 | require File.expand_path('../../test_helper', __FILE__)
2 |
3 | module Gmail
4 | class GmailObjectTest < Test::Unit::TestCase
5 | should "implement #respond_to correctly" do
6 | obj = Gmail::GmailObject.new({ :id => 1, :foo => 'bar' })
7 | assert_not_nil obj.id
8 | assert_not_nil obj.foo
9 | assert_nil obj.other
10 | end
11 |
12 | should "detail and refresh a Gmail object correctly" do
13 | obj = Gmail::GmailObject.new test_message
14 | exception = assert_raise do obj.refresh end
15 | assert_equal "Can't refresh a generic GmailObject. It needs to be a Thread, Message, Draft or Label", exception.message
16 | exception = assert_raise do obj.detailed end
17 | assert_equal "Can't detail a generic GmailObject. It needs to be a Thread, Message, Draft or Label", exception.message
18 |
19 | not_generic_object = Gmail::Message.new test_message
20 | @mock.expects(:execute).with(api_method: Gmail.service.users.messages.get, parameters: {userId: "me", id: test_message[:id]}, headers: {'Content-Type' => 'application/json'}).twice.returns(test_response(test_message))
21 |
22 | new_o = not_generic_object.detailed
23 | assert_not_equal new_o.object_id, not_generic_object.object_id
24 |
25 | new_o = not_generic_object.refresh
26 | assert_equal new_o.object_id, not_generic_object.object_id
27 |
28 | end
29 |
30 | should "recursively call to_hash on GmailObject" do
31 | nested = Gmail::GmailObject.new({ :id => 7, :foo => 'bar' })
32 | obj = Gmail::GmailObject.new({ :id => 1})
33 | obj.nested = nested
34 | expected_hash = { :id => 1, :nested => {:id => 7, :foo => 'bar'} }
35 | assert_equal expected_hash, obj.to_hash
36 | end
37 |
38 | end
39 | end
--------------------------------------------------------------------------------
/test/gmail/label_test.rb:
--------------------------------------------------------------------------------
1 | # -*- coding: utf-8 -*-
2 | require File.expand_path('../../test_helper', __FILE__)
3 |
4 | module Gmail
5 | class LabelTest < Test::Unit::TestCase
6 |
7 | should "Labels should be listable" do
8 | @mock.expects(:execute).with(api_method: Gmail.service.users.labels.list, parameters: {userId: "me"}, headers: {'Content-Type' => 'application/json'}).once.returns(test_response(test_label_list))
9 | list = Gmail::Label.all
10 | assert list.kind_of? Array
11 | assert list[0].kind_of? Gmail::Label
12 | end
13 |
14 |
15 | context "Retrieve a Label" do
16 | should "Label should be retrievable by id" do
17 |
18 | @mock.expects(:execute).with(api_method: Gmail.service.users.labels.get, parameters: {userId: "me", id: test_label[:id]}, headers: {'Content-Type' => 'application/json'}).once.returns(test_response(test_label))
19 | l = Gmail::Label.get(test_label[:id])
20 | assert l.kind_of?Gmail::Label
21 | assert_equal test_label[:id], l.id
22 | end
23 |
24 |
25 | [:inbox, :sent, :trash, :important, :starred, :draft, :spam, :unread, :category_updates, :category_promotions, :category_social, :category_personal, :category_forums ].each do |label_id|
26 | should "System Label should be retrievable by calling #{label_id.to_s}" do
27 | @mock.expects(:execute).with(api_method: Gmail.service.users.labels.get, parameters: {userId: "me", id: label_id.to_s.upcase}, headers: {'Content-Type' => 'application/json'}).once.returns(test_response(test_label_list[:labels].select{|l| l[:id] == label_id.to_s.upcase}.first))
28 | l = Gmail::Label.send(label_id.to_s)
29 | assert l.kind_of?Gmail::Label
30 | assert_equal label_id.to_s.upcase, l.id
31 | end
32 | end
33 |
34 | end
35 |
36 |
37 | context "Access list of Messages from Label" do
38 | should "Access list of Messages" do
39 | label = Gmail::Label.new test_label
40 | @mock.expects(:execute).with(api_method: Gmail.service.users.messages.list, parameters: {userId: "me", labelIds: [test_label[:id]]}, headers: {'Content-Type' => 'application/json'}).once.returns(test_response(test_message_list))
41 | list = label.messages
42 | assert list.kind_of? Array
43 | assert list[0].kind_of? Gmail::Message
44 | end
45 |
46 | should 'Access list of unread Messages' do
47 | label = Gmail::Label.new test_label
48 | @mock.expects(:execute).with(api_method: Gmail.service.users.messages.list, parameters: {userId: "me", labelIds: [test_label[:id], "UNREAD"]}, headers: {'Content-Type' => 'application/json'}).once.returns(test_response(test_message_list))
49 | list = label.unread_messages
50 | assert list.kind_of? Array
51 | assert list[0].kind_of? Gmail::Message
52 | end
53 |
54 | should 'Access filtered Messages' do
55 | label = Gmail::Label.new test_label
56 | @mock.expects(:execute).with(api_method: Gmail.service.users.messages.list, parameters: {userId: "me", labelIds: ["IMPORTANT", "COOL", test_label[:id]], threadId: "1"}, headers: {'Content-Type' => 'application/json'}).once.returns(test_response(test_message_list))
57 | list = label.messages(threadId: "1", labelIds: ["IMPORTANT", "COOL"])
58 | assert list.kind_of? Array
59 | assert list[0].kind_of? Gmail::Message
60 | end
61 |
62 | should "Access list of Threads" do
63 | label = Gmail::Label.new test_label
64 | @mock.expects(:execute).with(api_method: Gmail.service.users.threads.list, parameters: {userId: "me", labelIds: [test_label[:id]]}, headers: {'Content-Type' => 'application/json'}).once.returns(test_response(test_thread_list))
65 | list = label.threads
66 | assert list.kind_of? Array
67 | assert list[0].kind_of? Gmail::Thread
68 | end
69 |
70 | should 'Access list of unread Threads' do
71 | label = Gmail::Label.new test_label
72 | @mock.expects(:execute).with(api_method: Gmail.service.users.threads.list, parameters: {userId: "me", labelIds: [test_label[:id], "UNREAD"]}, headers: {'Content-Type' => 'application/json'}).once.returns(test_response(test_thread_list))
73 | list = label.unread_threads
74 | assert list.kind_of? Array
75 | assert list[0].kind_of? Gmail::Thread
76 | end
77 |
78 | should 'Access filtered Threads' do
79 | label = Gmail::Label.new test_label
80 | @mock.expects(:execute).with(api_method: Gmail.service.users.threads.list, parameters: {userId: "me", labelIds: ["IMPORTANT", "COOL", test_label[:id]], threadId: "1"}, headers: {'Content-Type' => 'application/json'}).once.returns(test_response(test_thread_list))
81 | list = label.threads(threadId: "1", labelIds: ["IMPORTANT", "COOL"])
82 | assert list.kind_of? Array
83 | assert list[0].kind_of? Gmail::Thread
84 | end
85 |
86 |
87 |
88 | end
89 |
90 |
91 | should "Label should be deletable" do
92 | @mock.expects(:execute).with(api_method: Gmail.service.users.labels.delete, parameters: {userId: "me", id: test_label[:id]}, headers: {'Content-Type' => 'application/json'}).once.returns(test_response(""))
93 | d = Gmail::Label.new(test_label)
94 | r = d.delete
95 | assert r
96 | end
97 |
98 | should "Label should be updateable" do
99 |
100 | label = Gmail::Label.new test_label(:messageListVisibility=>"show")
101 |
102 | assert_equal "show", label.messageListVisibility
103 |
104 |
105 | @mock.expects(:execute).with(api_method: Gmail.service.users.labels.update, parameters: {id: test_label[:id], userId: "me"}, body_object:test_label(:messageListVisibility=>"hide") , headers: {'Content-Type' => 'application/json'}).twice.returns(test_response(test_label(:messageListVisibility=>"hide")))
106 |
107 | label.messageListVisibility = "hide"
108 | new_l = label.save
109 | assert_equal "hide", new_l.messageListVisibility
110 | assert_not_equal label.object_id, new_l.object_id
111 | new_l = label.save!
112 | assert_equal label.object_id, new_l.object_id
113 | end
114 |
115 | should "create should return a new Label" do
116 | label_hash = test_label
117 | label_hash.delete(:id)
118 | label = Gmail::Label.new label_hash
119 | @mock.expects(:execute).with(api_method: Gmail.service.users.labels.create, parameters: {userId: "me"}, body_object:label_hash , headers: {'Content-Type' => 'application/json'}).once.returns(test_response(test_label))
120 | created_l = label.save!
121 | assert_equal Gmail::Label, created_l.class
122 | assert_equal test_label[:id], label.id
123 | end
124 |
125 |
126 |
127 |
128 | end
129 | end
--------------------------------------------------------------------------------
/test/gmail/message_test.rb:
--------------------------------------------------------------------------------
1 | # -*- coding: utf-8 -*-
2 | # encoding: utf-8
3 | require File.expand_path('../../test_helper', __FILE__)
4 |
5 | module Gmail
6 | class MessageTest < Test::Unit::TestCase
7 |
8 | should "messages should be listable" do
9 | @mock.expects(:execute).with(api_method: Gmail.service.users.messages.list, parameters: {userId: "me"}, headers: {'Content-Type' => 'application/json'}).once.returns(test_response(test_message_list))
10 | list = Gmail::Message.all
11 | assert_equal Array, list.class
12 | assert_equal Gmail::Message, list[0].class
13 | end
14 |
15 | should "message should be retrievable by id" do
16 |
17 | @mock.expects(:execute).with(api_method: Gmail.service.users.messages.get, parameters: {userId: "me", id: test_message[:id]}, headers: {'Content-Type' => 'application/json'}).once.returns(test_response(test_message))
18 | t = Gmail::Message.get(test_message[:id])
19 | assert_equal Gmail::Message, t.class
20 | assert_equal test_message[:id], t.id
21 | end
22 |
23 | should "message construct should set some basics values" do
24 |
25 | m = Gmail::Message.new(test_message)
26 | ["From", "To", "Cc", "Subject", "Bcc", "Date", "Message-ID", "References", "In-Reply-To", "Delivered-To"].each do |method|
27 | assert_equal test_message[:payload][:headers].select{|h| h[:name].downcase == method.downcase}.first[:value], m.send(method.downcase.tr("-", "_"))
28 | end
29 | assert_not_nil m.text || m.body || m.html
30 |
31 | end
32 |
33 | should "message (with strange format) construct should set at least body, text or html" do
34 |
35 | m = Gmail::Message.new(test_strange_message)
36 | assert_not_nil m.text || m.body || m.html
37 |
38 | end
39 |
40 |
41 |
42 |
43 | should "Access thread from message" do
44 | @mock.expects(:execute).with(api_method: Gmail.service.users.threads.get, parameters: {userId: "me", id: test_message[:threadId]}, headers: {'Content-Type' => 'application/json'}).once.returns(test_response(test_thread))
45 | m = Gmail::Message.new(test_message)
46 | t = m.thread
47 | assert_equal test_message[:threadId], m.thread_id
48 | assert_equal Gmail::Thread, t.class
49 | end
50 |
51 | should "message should be deletable" do
52 | @mock.expects(:execute).with(api_method: Gmail.service.users.messages.delete, parameters: {userId: "me", id: test_message[:id]}, headers: {'Content-Type' => 'application/json'}).once.returns(test_response(""))
53 | t = Gmail::Message.new(test_message)
54 | r = t.delete
55 | assert r
56 | end
57 |
58 | should "message should be thrashable" do
59 | @mock.expects(:execute).with(api_method: Gmail.service.users.messages.trash, parameters: {userId: "me", id: test_message[:id]}, headers: {'Content-Type' => 'application/json'}).once.returns(test_response(test_message))
60 | t = Gmail::Message.new(test_message)
61 | r = t.trash
62 | assert_equal Gmail::Message, r.class
63 | end
64 |
65 | should "message should be unthrashable" do
66 | @mock.expects(:execute).with(api_method: Gmail.service.users.messages.untrash, parameters: {userId: "me", id: test_message[:id]}, headers: {'Content-Type' => 'application/json'}).once.returns(test_response(test_message))
67 | t = Gmail::Message.new(test_message)
68 | r = t.untrash
69 | assert_equal Gmail::Message, r.class
70 | end
71 |
72 | context "Modifying Labels" do
73 | should "message should be starrable" do
74 | @mock.expects(:execute).with(api_method: Gmail.service.users.messages.modify, parameters: {userId: "me", id: test_message[:id]}, body_object: {addLabelIds: ["STARRED"], removeLabelIds: []} , headers: {'Content-Type' => 'application/json'}).twice.returns(test_response(test_message))
75 | t = Gmail::Message.new(test_message)
76 | r = t.star
77 | assert_equal Gmail::Message, r.class
78 | assert_not_equal t.object_id, r.object_id
79 |
80 | r = t.star!
81 |
82 | assert_equal t.object_id, r.object_id
83 |
84 | end
85 |
86 | should "message should be unstarrable" do
87 | @mock.expects(:execute).with(api_method: Gmail.service.users.messages.modify, parameters: {userId: "me", id: test_message[:id]}, body_object: {addLabelIds: [], removeLabelIds: ["STARRED"]} , headers: {'Content-Type' => 'application/json'}).twice.returns(test_response(test_message))
88 | t = Gmail::Message.new(test_message)
89 | r = t.unstar
90 | assert_equal Gmail::Message, r.class
91 |
92 | assert_not_equal t.object_id, r.object_id
93 |
94 | r = t.unstar!
95 |
96 | assert_equal t.object_id, r.object_id
97 | end
98 |
99 | should "message should be archivable" do
100 | @mock.expects(:execute).with(api_method: Gmail.service.users.messages.modify, parameters: {userId: "me", id: test_message[:id]}, body_object: {addLabelIds: [], removeLabelIds: ["INBOX"]} , headers: {'Content-Type' => 'application/json'}).twice.returns(test_response(test_message))
101 | t = Gmail::Message.new(test_message)
102 | r = t.archive
103 | assert_equal Gmail::Message, r.class
104 | assert_not_equal t.object_id, r.object_id
105 |
106 | r = t.archive!
107 |
108 | assert_equal t.object_id, r.object_id
109 | end
110 |
111 | should "message should be unarchivable" do
112 | @mock.expects(:execute).with(api_method: Gmail.service.users.messages.modify, parameters: {userId: "me", id: test_message[:id]}, body_object: {addLabelIds: ["INBOX"], removeLabelIds: []} , headers: {'Content-Type' => 'application/json'}).twice.returns(test_response(test_message))
113 | t = Gmail::Message.new(test_message)
114 | r = t.unarchive
115 | assert_equal Gmail::Message, r.class
116 | assert_not_equal t.object_id, r.object_id
117 |
118 | r = t.unarchive!
119 |
120 | assert_equal t.object_id, r.object_id
121 | end
122 |
123 | should "message should be markable as read" do
124 | @mock.expects(:execute).with(api_method: Gmail.service.users.messages.modify, parameters: {userId: "me", id: test_message[:id]}, body_object: {addLabelIds: [], removeLabelIds: ["UNREAD"]} , headers: {'Content-Type' => 'application/json'}).twice.returns(test_response(test_message))
125 | t = Gmail::Message.new(test_message)
126 | r = t.mark_as_read
127 | assert_equal Gmail::Message, r.class
128 | assert_not_equal t.object_id, r.object_id
129 |
130 | r = t.mark_as_read!
131 |
132 | assert_equal t.object_id, r.object_id
133 | end
134 |
135 | should "message should be markable as unread" do
136 | @mock.expects(:execute).with(api_method: Gmail.service.users.messages.modify, parameters: {userId: "me", id: test_message[:id]}, body_object: {addLabelIds: ["UNREAD"], removeLabelIds: []} , headers: {'Content-Type' => 'application/json'}).twice.returns(test_response(test_message))
137 | t = Gmail::Message.new(test_message)
138 | r = t.mark_as_unread
139 | assert_equal Gmail::Message, r.class
140 | assert_not_equal t.object_id, r.object_id
141 |
142 | r = t.mark_as_unread!
143 |
144 | assert_equal t.object_id, r.object_id
145 | end
146 |
147 |
148 | should "message label should be modifiable as wish" do
149 | @mock.expects(:execute).with(api_method: Gmail.service.users.messages.modify, parameters: {userId: "me", id: test_message[:id]}, body_object: {addLabelIds: ["UNREAD", "SOME COOL LABEL"], removeLabelIds: ["INBOX", "SOME NOT COOL LABEL"]} , headers: {'Content-Type' => 'application/json'}).twice.returns(test_response(test_message))
150 | t = Gmail::Message.new(test_message)
151 | r = t.modify ["UNREAD", "SOME COOL LABEL"], ["INBOX", "SOME NOT COOL LABEL"]
152 | assert_equal Gmail::Message, r.class
153 | assert_not_equal t.object_id, r.object_id
154 |
155 | r = t.modify! ["UNREAD", "SOME COOL LABEL"], ["INBOX", "SOME NOT COOL LABEL"]
156 |
157 | assert_equal t.object_id, r.object_id
158 | end
159 |
160 | end
161 |
162 |
163 | should "Helpers should work" do
164 | m = Gmail::Message.new test_message
165 | assert_false m.sent?
166 | assert_false m.inbox?
167 | assert_false m.unread?
168 | m = Gmail::Message.new test_inbox_message
169 | assert_false m.sent?
170 | assert m.inbox?
171 | assert_false m.unread?
172 | m = Gmail::Message.new test_sent_message
173 | assert m.sent?
174 | assert_false m.inbox?
175 | assert_false m.unread?
176 | m = Gmail::Message.new test_unread_message
177 | assert_false m.sent?
178 | assert_false m.inbox?
179 | assert m.unread?
180 | end
181 |
182 |
183 | should "Message should be searcheable" do
184 | @mock.expects(:execute).with(api_method: Gmail.service.users.messages.list, parameters: {userId: "me", q: "from:(me) to:(you) subject:(subject) in:inbox before:2014/12/1 after:2014/11/1 test -{real}", labelIds:["UNREAD"]}, headers: {'Content-Type' => 'application/json'}).once.returns(test_response(test_message_list))
185 | list = Gmail::Message.search(from:"me", to: "you", subject: "subject", in: "inbox", before: "2014/12/1", after: "2014/11/1", has_words: "test", has_not_words: "real", labelIds: ["UNREAD"])
186 | assert_equal Array, list.class
187 | assert_equal Gmail::Message, list[0].class
188 | end
189 |
190 | should "Message should construct RAW string correctly" do
191 | m = Gmail::Message.new test_message
192 | raw = Mail.new(Base64.urlsafe_decode64(m.raw))
193 | assert raw.from
194 | assert raw.to
195 | assert raw.cc
196 | assert_equal m.bcc, raw.header['Bcc'].value
197 | assert_equal m.subject, raw.subject
198 | assert_equal m.in_reply_to, "<#{raw.in_reply_to}>"
199 | assert_equal m.references.tr("<", "").tr(">", "").split(" "), raw.references
200 | assert raw.text_part.body.raw_source
201 | assert raw.html_part.body.raw_source
202 | end
203 |
204 | should "Draft can be created from Message" do
205 | m = Gmail::Message.new test_message
206 | # raw generation change between two calls because date won't be the same...
207 | m.raw = m.raw
208 | ###
209 | @mock.expects(:execute).with(api_method: Gmail.service.users.drafts.create, parameters: {userId: "me"}, body_object:{message: {raw: m.raw, threadId: test_message[:threadId], labelIds: test_message[:labelIds]}} , headers: {'Content-Type' => 'application/json'}).once.returns(test_response(test_draft))
210 | d = m.create_draft
211 | assert_equal Gmail::Draft, d.class
212 |
213 | end
214 |
215 | should "Message should be sendable and return a Message" do
216 |
217 | m = Gmail::Message.new test_message
218 | m.raw = m.raw
219 | @mock.expects(:execute).with(api_method: Gmail.service.users.messages.to_h['gmail.users.messages.send'], parameters: {userId: "me"}, body_object:{raw: m.raw, labelIds: test_message[:labelIds], threadId: test_message[:threadId]} , headers: {'Content-Type' => 'application/json'}).twice.returns(test_response(test_message))
220 |
221 | @mock.expects(:execute).with(api_method: Gmail.service.users.messages.get, parameters: {userId: "me", id: test_message[:id]}, headers: {'Content-Type' => 'application/json'}).twice.returns(test_response(test_message))
222 |
223 |
224 | new_m = m.deliver
225 | assert_equal Gmail::Message, new_m.class
226 | assert_not_equal new_m.object_id, m.object_id
227 |
228 | new_m = m.deliver!
229 | assert_equal Gmail::Message, new_m.class
230 | assert_equal new_m.object_id, m.object_id
231 | end
232 |
233 |
234 | should "Reply to sender contruct should be easy" do
235 | m = Gmail::Message.new test_to_reply_message
236 | reply_message = Gmail::Message.new test_reply_message
237 | @mock.expects(:execute).never
238 | expected_msg = Gmail::Message.new test_replied_message
239 | new_m = m.reply_sender_with reply_message
240 |
241 | assert_equal expected_msg.to, new_m.to
242 | assert_nil new_m.cc
243 | assert_nil new_m.bcc
244 | assert_equal expected_msg.subject, new_m.subject
245 | assert_equal expected_msg.references, new_m.references
246 | assert_equal expected_msg.in_reply_to, new_m.in_reply_to
247 | assert_equal expected_msg.thread_id, new_m.thread_id
248 | assert_equal expected_msg.body, new_m.body
249 | assert_nil new_m.html
250 | assert_nil new_m.text
251 |
252 | new_m = m.reply_sender_with(Gmail::Message.new test_reply_message_with_html)
253 | expected_msg = Gmail::Message.new(test_replied_message_with_html)
254 |
255 | assert_equal expected_msg.text, new_m.text
256 | assert_equal expected_msg.html, new_m.html
257 | assert_nil new_m.body
258 |
259 | end
260 |
261 | should "Reply to all construct should be easy" do
262 | m = Gmail::Message.new test_to_reply_message
263 | reply_message = Gmail::Message.new test_reply_message
264 | @mock.expects(:execute).never
265 | new_m = m.reply_all_with reply_message
266 | expected_msg = Gmail::Message.new test_replied_message
267 |
268 | assert_equal expected_msg.to, new_m.to
269 | assert_equal expected_msg.cc, new_m.cc
270 | assert_nil new_m.bcc
271 | assert_equal expected_msg.subject, new_m.subject
272 | assert_equal expected_msg.references, new_m.references
273 | assert_equal expected_msg.in_reply_to, new_m.in_reply_to
274 | assert_equal expected_msg.thread_id, new_m.thread_id
275 | assert_equal expected_msg.body, new_m.body
276 | assert_nil new_m.html
277 | assert_nil new_m.text
278 |
279 | new_m = m.reply_all_with(Gmail::Message.new test_reply_message_with_html)
280 | expected_msg = Gmail::Message.new(test_replied_message_with_html)
281 |
282 | assert_equal expected_msg.text, new_m.text
283 | assert_equal expected_msg.html, new_m.html
284 | assert_nil new_m.body
285 |
286 |
287 | end
288 |
289 | should "Construct correctly set_headers_for_reply" do
290 | m = Gmail::Message.new({body: ""})
291 | m.from = "\"John, Malkovich\" john@malkovich.com"
292 | m.to = "\"Julie, Desk\"julie@juliedesk.com, \"Judith, Desk\"judith@juliedesk.com"
293 | m.delivered_to = "julie@juliedesk.com"
294 | new_msg = m.send(:set_headers_for_reply, Gmail::Message.new({body: ""}))
295 |
296 | #assert_equal new_msg.from, "\"Julie, Desk\"julie@juliedesk.com"
297 | assert_equal new_msg.to, "\"John, Malkovich\" john@malkovich.com"
298 | assert_equal new_msg.cc, "\"Judith, Desk\"judith@juliedesk.com"
299 | end
300 |
301 | should "Reply to all construct should be easy and call getProfile if delivered_to is not set" do
302 | m = Gmail::Message.new test_to_reply_message2
303 | reply_message = Gmail::Message.new test_reply_message
304 | @mock.expects(:execute).with(api_method: Gmail.service.users.to_h['gmail.users.getProfile'],parameters: {userId: "me"} , headers: {'Content-Type' => 'application/json'}).once.returns(test_response({emailAddress: "julie@juliedesk.com"}))
305 | new_m = m.reply_all_with reply_message
306 | expected_msg = Gmail::Message.new test_replied_message
307 |
308 | assert_equal expected_msg.to, new_m.to
309 | assert_equal expected_msg.cc, new_m.cc
310 | assert_nil new_m.bcc
311 | assert_equal expected_msg.subject, new_m.subject
312 | assert_equal expected_msg.references, new_m.references
313 | assert_equal expected_msg.in_reply_to, new_m.in_reply_to
314 | assert_equal expected_msg.thread_id, new_m.thread_id
315 | assert_equal expected_msg.body, new_m.body
316 | assert_nil new_m.html
317 | assert_nil new_m.text
318 |
319 |
320 | end
321 |
322 | should "forward construct should be easy" do
323 | m = Gmail::Message.new test_to_reply_message
324 | forward_message = Gmail::Message.new(test_forward_message)
325 | @mock.expects(:execute).never
326 | new_m = m.forward_with forward_message
327 | expected_msg = Gmail::Message.new test_forwarded_message
328 | # to be completed to be fully tested
329 |
330 | assert_equal expected_msg.to, new_m.to
331 | assert_equal expected_msg.cc, new_m.cc
332 | assert_nil new_m.bcc
333 | assert_equal expected_msg.subject, new_m.subject
334 | assert_equal expected_msg.references, new_m.references
335 | assert_equal expected_msg.in_reply_to, new_m.in_reply_to
336 | assert_equal expected_msg.thread_id, new_m.thread_id
337 | assert_equal expected_msg.body, new_m.body
338 | assert_nil new_m.html
339 | assert_nil new_m.text
340 |
341 | forward_message = Gmail::Message.new({to: "test@test.com", bbc: "coucou", cc: "test@couocu.com, second@second.com", subject: "cool subject", html: "test", text: "test"})
342 | new_m = m.forward_with forward_message
343 | expected_msg = Gmail::Message.new test_forwarded_message_with_html
344 |
345 | assert_equal expected_msg.text, new_m.text
346 | assert_equal expected_msg.html, new_m.html
347 | assert_nil new_m.body
348 | end
349 |
350 | should "Insert call should be easy" do
351 | m = Gmail::Message.new test_message
352 | m.raw = m.raw
353 | @mock.expects(:execute).with(api_method: Gmail.service.users.messages.insert, parameters: {userId: "me"}, body_object:{raw: m.raw, labelIds: test_message[:labelIds], threadId: test_message[:threadId]} , headers: {'Content-Type' => 'application/json'} ).twice.returns(test_response(test_message))
354 | @mock.expects(:execute).with(api_method: Gmail.service.users.messages.get, parameters: {userId: "me", id: test_message[:id]}, headers: {'Content-Type' => 'application/json'}).twice.returns(test_response(test_message))
355 |
356 |
357 | new_m = m.insert
358 |
359 | assert_not_equal m.object_id, new_m.object_id
360 | new_m = m.insert!
361 | assert_equal m.object_id, new_m.object_id
362 | end
363 |
364 | end
365 | end
--------------------------------------------------------------------------------
/test/gmail/thread_test.rb:
--------------------------------------------------------------------------------
1 | # -*- coding: utf-8 -*-
2 | require File.expand_path('../../test_helper', __FILE__)
3 |
4 | module Gmail
5 | class ThreadTest < Test::Unit::TestCase
6 |
7 | should "Threads should be listable" do
8 | @mock.expects(:execute).with(api_method: Gmail.service.users.threads.list, parameters: {userId: "me"}, headers: {'Content-Type' => 'application/json'}).once.returns(test_response(test_thread_list))
9 | list = Gmail::Thread.all
10 | assert_equal Array, list.class
11 | assert_equal Gmail::Thread, list[0].class
12 | end
13 |
14 | should "Thread should be retrievable by id" do
15 |
16 | @mock.expects(:execute).with(api_method: Gmail.service.users.threads.get, parameters: {userId: "me", id: test_thread[:id]}, headers: {'Content-Type' => 'application/json'}).once.returns(test_response(test_thread))
17 | t = Gmail::Thread.get(test_thread[:id])
18 | assert_equal Gmail::Thread, t.class
19 | assert_equal test_thread[:id], t.id
20 | end
21 |
22 |
23 | context "Access list of Messages from thread" do
24 | should "Access list of Messages" do
25 | thread = Gmail::Thread.new test_thread
26 | # @mock.expects(:execute).with(api_method: Gmail.service.users.messages.list, parameters: {userId: "me", threadId: [test_thread[:id]]}, headers: {'Content-Type' => 'application/json'}).once.returns(test_response(test_message_list))
27 | list = thread.messages
28 | assert_equal Array, list.class
29 | assert_equal Gmail::Message, list[0].class
30 | end
31 |
32 | should "Access list of Messages after selecting from list" do
33 | @mock.expects(:execute).with(api_method: Gmail.service.users.threads.list, parameters: {userId: "me"}, headers: {'Content-Type' => 'application/json'}).once.returns(test_response(test_thread_list))
34 | thread_list = Gmail::Thread.all
35 | @mock.expects(:execute).with(api_method: Gmail.service.users.threads.get, parameters: {userId: "me", id: test_thread[:id]}, headers: {'Content-Type' => 'application/json'}).once.returns(test_response(test_message_list))
36 | thread = thread_list.first
37 | list = thread.messages
38 | assert_equal Array, list.class
39 | assert_equal Gmail::Message, list[0].class
40 | end
41 |
42 |
43 | should 'Access list of unread Messages' do
44 | thread = Gmail::Thread.new test_thread
45 | #@mock.expects(:execute).with(api_method: Gmail.service.users.messages.list, parameters: {userId: "me", threadId: [test_thread[:id]], labelIds: ["UNREAD"]}, headers: {'Content-Type' => 'application/json'}).once.returns(test_response(test_message_list))
46 | list = thread.unread_messages
47 | assert_equal Array, list.class
48 | assert_equal Gmail::Message, list[0].class
49 | end
50 |
51 | should 'Access list of sent Messages' do
52 | thread = Gmail::Thread.new test_thread
53 | # @mock.expects(:execute).with(api_method: Gmail.service.users.messages.list, parameters: {userId: "me", threadId: [test_thread[:id]], labelIds: ["SENT"]}, headers: {'Content-Type' => 'application/json'}).once.returns(test_response(test_message_list))
54 | list = thread.unread_messages
55 | assert_equal Array, list.class
56 | assert_equal Gmail::Message, list[0].class
57 | end
58 | end
59 |
60 |
61 | should "Thread should be deletable" do
62 | @mock.expects(:execute).with(api_method: Gmail.service.users.threads.delete, parameters: {userId: "me", id: test_thread[:id]}, headers: {'Content-Type' => 'application/json'}).once.returns(test_response(""))
63 | t = Gmail::Thread.new(test_thread)
64 | r = t.delete
65 | assert r
66 | end
67 |
68 | should "Thread should be thrashable" do
69 | @mock.expects(:execute).with(api_method: Gmail.service.users.threads.trash, parameters: {userId: "me", id: test_thread[:id]}, headers: {'Content-Type' => 'application/json'}).once.returns(test_response(test_thread))
70 | t = Gmail::Thread.new(test_thread)
71 | r = t.trash
72 | assert_equal Gmail::Thread, r.class
73 | end
74 |
75 | should "Thread should be unthrashable" do
76 | @mock.expects(:execute).with(api_method: Gmail.service.users.threads.untrash, parameters: {userId: "me", id: test_thread[:id]}, headers: {'Content-Type' => 'application/json'}).once.returns(test_response(test_thread))
77 | t = Gmail::Thread.new(test_thread)
78 | r = t.untrash
79 | assert_equal Gmail::Thread, r.class
80 | end
81 |
82 | context "Modifying Labels" do
83 | should "Thread should be starrable" do
84 | @mock.expects(:execute).with(api_method: Gmail.service.users.threads.modify, parameters: {userId: "me", id: test_thread[:id]}, body_object: {addLabelIds: ["STARRED"], removeLabelIds: []} , headers: {'Content-Type' => 'application/json'}).twice.returns(test_response(test_thread))
85 | t = Gmail::Thread.new(test_thread)
86 | r = t.star
87 | assert_equal Gmail::Thread, r.class
88 | assert_not_equal t.object_id, r.object_id
89 |
90 | r = t.star!
91 |
92 | assert_equal t.object_id, r.object_id
93 |
94 | end
95 |
96 | should "Thread should be unstarrable" do
97 | @mock.expects(:execute).with(api_method: Gmail.service.users.threads.modify, parameters: {userId: "me", id: test_thread[:id]}, body_object: {addLabelIds: [], removeLabelIds: ["STARRED"]} , headers: {'Content-Type' => 'application/json'}).twice.returns(test_response(test_thread))
98 | t = Gmail::Thread.new(test_thread)
99 | r = t.unstar
100 | assert_equal Gmail::Thread, r.class
101 |
102 | assert_not_equal t.object_id, r.object_id
103 |
104 | r = t.unstar!
105 |
106 | assert_equal t.object_id, r.object_id
107 | end
108 |
109 | should "Thread should be archivable" do
110 | @mock.expects(:execute).with(api_method: Gmail.service.users.threads.modify, parameters: {userId: "me", id: test_thread[:id]}, body_object: {addLabelIds: [], removeLabelIds: ["INBOX"]} , headers: {'Content-Type' => 'application/json'}).twice.returns(test_response(test_thread))
111 | t = Gmail::Thread.new(test_thread)
112 | r = t.archive
113 | assert_equal Gmail::Thread, r.class
114 | assert_not_equal t.object_id, r.object_id
115 |
116 | r = t.archive!
117 |
118 | assert_equal t.object_id, r.object_id
119 | end
120 |
121 | should "Thread should be unarchivable" do
122 | @mock.expects(:execute).with(api_method: Gmail.service.users.threads.modify, parameters: {userId: "me", id: test_thread[:id]}, body_object: {addLabelIds: ["INBOX"], removeLabelIds: []} , headers: {'Content-Type' => 'application/json'}).twice.returns(test_response(test_thread))
123 | t = Gmail::Thread.new(test_thread)
124 | r = t.unarchive
125 | assert_equal Gmail::Thread, r.class
126 | assert_not_equal t.object_id, r.object_id
127 |
128 | r = t.unarchive!
129 |
130 | assert_equal t.object_id, r.object_id
131 | end
132 |
133 | should "Thread should be markable as read" do
134 | @mock.expects(:execute).with(api_method: Gmail.service.users.threads.modify, parameters: {userId: "me", id: test_thread[:id]}, body_object: {addLabelIds: [], removeLabelIds: ["UNREAD"]} , headers: {'Content-Type' => 'application/json'}).twice.returns(test_response(test_thread))
135 | t = Gmail::Thread.new(test_thread)
136 | r = t.mark_as_read
137 | assert_equal Gmail::Thread, r.class
138 | assert_not_equal t.object_id, r.object_id
139 |
140 | r = t.mark_as_read!
141 |
142 | assert_equal t.object_id, r.object_id
143 | end
144 |
145 | should "Thread should be markable as unread" do
146 | @mock.expects(:execute).with(api_method: Gmail.service.users.threads.modify, parameters: {userId: "me", id: test_thread[:id]}, body_object: {addLabelIds: ["UNREAD"], removeLabelIds: []} , headers: {'Content-Type' => 'application/json'}).twice.returns(test_response(test_thread))
147 | t = Gmail::Thread.new(test_thread)
148 | r = t.mark_as_unread
149 | assert_equal Gmail::Thread, r.class
150 | assert_not_equal t.object_id, r.object_id
151 |
152 | r = t.mark_as_unread!
153 |
154 | assert_equal t.object_id, r.object_id
155 | end
156 |
157 |
158 | should "Thread label should be modifiable as wish" do
159 | @mock.expects(:execute).with(api_method: Gmail.service.users.threads.modify, parameters: {userId: "me", id: test_thread[:id]}, body_object: {addLabelIds: ["UNREAD", "SOME COOL LABEL"], removeLabelIds: ["INBOX", "SOME NOT COOL LABEL"]} , headers: {'Content-Type' => 'application/json'}).twice.returns(test_response(test_thread))
160 | t = Gmail::Thread.new(test_thread)
161 | r = t.modify ["UNREAD", "SOME COOL LABEL"], ["INBOX", "SOME NOT COOL LABEL"]
162 | assert_equal Gmail::Thread, r.class
163 | assert_not_equal t.object_id, r.object_id
164 |
165 | r = t.modify! ["UNREAD", "SOME COOL LABEL"], ["INBOX", "SOME NOT COOL LABEL"]
166 |
167 | assert_equal t.object_id, r.object_id
168 | end
169 |
170 | end
171 |
172 |
173 | should "Thread should be searcheable" do
174 | @mock.expects(:execute).with(api_method: Gmail.service.users.threads.list, parameters: {userId: "me", q: "from:(me) to:(you) subject:(subject) in:inbox before:2014/12/1 after:2014/11/1 test -{real}", labelIds:["UNREAD"]}, headers: {'Content-Type' => 'application/json'}).once.returns(test_response(test_thread_list))
175 | list = Gmail::Thread.search(from:"me", to: "you", subject: "subject", in: "inbox", before: "2014/12/1", after: "2014/11/1", has_words: "test", has_not_words: "real", labelIds: ["UNREAD"])
176 | assert_equal Array, list.class
177 | assert_equal Gmail::Thread, list[0].class
178 | end
179 |
180 |
181 |
182 |
183 | end
184 | end
--------------------------------------------------------------------------------
/test/gmail/util_test.rb:
--------------------------------------------------------------------------------
1 | # -*- coding: utf-8 -*-
2 | require File.expand_path('../../test_helper', __FILE__)
3 |
4 | module Gmail
5 | class UtilTest < Test::Unit::TestCase
6 |
7 | should "Symbolize Name should work properly" do
8 | assert_equal(({:test1=> "test"}), Gmail::Util.symbolize_names({"test1"=>'test'}))
9 | m =Gmail::Message.new test_message
10 | assert_equal m, Gmail::Util.symbolize_names(m)
11 | assert_equal(({test: {nested:[{coucou: "1", coucou2: "2"}]}}), Gmail::Util.symbolize_names({"test"=>{"nested"=>[{"coucou"=>"1","coucou2"=>"2"}]}}))
12 | assert_equal [{coucou: "1", coucou2: "2"}], Gmail::Util.symbolize_names([{"coucou"=>"1", "coucou2"=>"2"}])
13 | end
14 |
15 | #testing of convert_to_gmail_object is not necessary as it is tested through all other test files
16 |
17 | end
18 | end
--------------------------------------------------------------------------------
/test/test_data.rb:
--------------------------------------------------------------------------------
1 | # -*- coding: utf-8 -*-
2 | module Gmail
3 | module TestData
4 | def test_response(body, code=200)
5 | # When an exception is raised, restclient clobbers method_missing. Hence we
6 | # can't just use the stubs interface.
7 | body = JSON.generate(body) if !(body.kind_of? String)
8 | m = mock
9 | m.instance_variable_set('@gmail_values', { :body => body, :code => code })
10 | def m.body; @gmail_values[:body]; end
11 | def m.code; @gmail_values[:code]; end
12 | m
13 | end
14 |
15 | def test_draft(params={})
16 | {:id=>"1490204870554280932", :message=>{:id=>"14ae456f2ff1e3e4", :threadId=>"14ae456f2ff1e3e4", :labelIds=>["DRAFT"], :snippet=>"sd Cordialement, Julie", :historyId=>"227960", :payload=>{:mimeType=>"multipart/alternative", :filename=>"", :headers=>[{:name=>"MIME-Version", :value=>"1.0"}, {:name=>"Received", :value=>"by 10.64.21.4 with HTTP; Tue, 13 Jan 2015 09:28:31 -0800 (PST)"}, {:name=>"Date", :value=>"Tue, 13 Jan 2015 18:28:31 +0100"}, {:name=>"Message-ID", :value=>""}, {:name=>"Subject", :value=>""}, {:name=>"From", :value=>"Julie Desk "}, {:name=>"Content-Type", :value=>"multipart/alternative; boundary=f46d042abf34a36bd9050c8bf335"}], :body=>{:size=>0}, :parts=>[{:partId=>"0", :mimeType=>"text/plain", :filename=>"", :headers=>[{:name=>"Content-Type", :value=>"text/plain; charset=UTF-8"}], :body=>{:size=>28, :data=>"c2QNCkNvcmRpYWxlbWVudCwNCg0KSnVsaWUNCg=="}}, {:partId=>"1", :mimeType=>"text/html", :filename=>"", :headers=>[{:name=>"Content-Type", :value=>"text/html; charset=UTF-8"}], :body=>{:size=>154, :data=>"PGRpdiBkaXI9Imx0ciI-c2Q8YnIgY2xlYXI9ImFsbCI-PGRpdj48ZGl2IGNsYXNzPSJnbWFpbF9zaWduYXR1cmUiPjxkaXYgZGlyPSJsdHIiPkNvcmRpYWxlbWVudCw8ZGl2Pjxicj48L2Rpdj48ZGl2Pkp1bGllPC9kaXY-PC9kaXY-PC9kaXY-PC9kaXY-DQo8L2Rpdj4NCg=="}}]}, :sizeEstimate=>710}} .merge(params)
17 |
18 | end
19 |
20 |
21 | def test_strange_message #it has payload.parts.parts
22 | {:id=>"14ae95209c15af0a", :threadId=>"14ae94601bae5138", :labelIds=>["IMPORTANT", "CATEGORY_PERSONAL"], :snippet=>"Bonjour Julie, Le plus tôt sera le mieux, j'ai hâte ! Je bloque le 12/02 Merci De : Julie Desk [", :historyId=>"231473", :payload=>{:mimeType=>"multipart/related", :filename=>"", :headers=>[{:name=>"Delivered-To", :value=>"julie@juliedesk.com"}, {:name=>"Received", :value=>"by 10.64.89.39 with SMTP id bl7csp1683249ieb; Wed, 14 Jan 2015 08:41:16 -0800 (PST)"}, {:name=>"X-Received", :value=>"by 10.194.76.205 with SMTP id m13mr8833652wjw.39.1421253675567; Wed, 14 Jan 2015 08:41:15 -0800 (PST)"}, {:name=>"Return-Path", :value=>""}, {:name=>"Received", :value=>"from emea01-am1-obe.outbound.protection.outlook.com (mail-am1on0770.outbound.protection.outlook.com. [2a01:111:f400:fe00::770]) by mx.google.com with ESMTPS id v10si5545148wix.4.2015.01.14.08.41.14 for (version=TLSv1.2 cipher=ECDHE-RSA-AES128-SHA bits=128/128); Wed, 14 Jan 2015 08:41:15 -0800 (PST)"}, {:name=>"Received-SPF", :value=>"pass (google.com: domain of sandra.perez@esnumerique.com designates 2a01:111:f400:fe00::770 as permitted sender) client-ip=2a01:111:f400:fe00::770;"}, {:name=>"Authentication-Results", :value=>"mx.google.com; spf=pass (google.com: domain of sandra.perez@esnumerique.com designates 2a01:111:f400:fe00::770 as permitted sender) smtp.mail=sandra.perez@esnumerique.com"}, {:name=>"Received", :value=>"from AMSPR06MB102.eurprd06.prod.outlook.com (10.242.90.147) by DB3PR06MB0937.eurprd06.prod.outlook.com (25.161.60.149) with Microsoft SMTP Server (TLS) id 15.1.53.17; Wed, 14 Jan 2015 16:41:13 +0000"}, {:name=>"Received", :value=>"from AMSPR06MB102.eurprd06.prod.outlook.com ([169.254.6.131]) by AMSPR06MB102.eurprd06.prod.outlook.com ([169.254.6.131]) with mapi id 15.01.0053.000; Wed, 14 Jan 2015 16:41:13 +0000"}, {:name=>"From", :value=>"Sandra Perez "}, {:name=>"To", :value=>"Julie Desk , Vincent Klingbeil "}, {:name=>"Subject", :value=>"RE: Dej"}, {:name=>"Thread-Topic", :value=>"Dej"}, {:name=>"Thread-Index", :value=>"AdAwFmdsGWjLpOTkSh6OGW1svRYHwwAAi/qAAAAdX/A="}, {:name=>"Date", :value=>"Wed, 14 Jan 2015 16:41:13 +0000"}, {:name=>"Message-ID", :value=>""}, {:name=>"References", :value=>" "}, {:name=>"In-Reply-To", :value=>""}, {:name=>"Accept-Language", :value=>"fr-FR, en-US"}, {:name=>"Content-Language", :value=>"fr-FR"}, {:name=>"X-MS-Has-Attach", :value=>"yes"}, {:name=>"X-MS-TNEF-Correlator", :value=>""}, {:name=>"x-originating-ip", :value=>"[88.162.203.104]"}, {:name=>"authentication-results", :value=>"spf=none (sender IP is ) smtp.mailfrom=sandra.perez@esnumerique.com;"}, {:name=>"x-dmarcaction-test", :value=>"None"}, {:name=>"x-microsoft-antispam", :value=>"BCL:0;PCL:0;RULEID:(3005003);SRVR:DB3PR06MB0937;"}, {:name=>"x-exchange-antispam-report-test", :value=>"UriScan:;"}, {:name=>"x-exchange-antispam-report-cfa-test", :value=>"BCL:0;PCL:0;RULEID:;SRVR:DB3PR06MB0937;"}, {:name=>"x-forefront-prvs", :value=>"04569283F9"}, {:name=>"x-forefront-antispam-report", :value=>"SFV:NSPM;SFS:(10019020)(199003)(377424004)(189002)(68736005)(54356999)(76176999)(18206015028)(40100003)(99936001)(54606007)(102836002)(15975445007)(106356001)(50986999)(77156002)(62966003)(19625215002)(16236675004)(92566002)(33656002)(2950100001)(2900100001)(105586002)(221733001)(97736003)(46102003)(2656002)(87936001)(16601075003)(19300405004)(17760045003)(54206007)(66066001)(76576001)(19580395003)(101416001)(86362001)(74316001)(19580405001)(122556002)(19617315012)(64706001)(107886001)(19627595001);DIR:OUT;SFP:1102;SCL:1;SRVR:DB3PR06MB0937;H:AMSPR06MB102.eurprd06.prod.outlook.com;FPR:;SPF:None;MLV:sfv;PTR:InfoNoRecords;A:1;MX:1;LANG:fr;"}, {:name=>"received-spf", :value=>"None (protection.outlook.com: esnumerique.com does not designate permitted sender hosts)"}, {:name=>"Content-Type", :value=>"multipart/related; boundary=\"_005_AMSPR06MB102CF5CA6B835FEA9E50E6D97410AMSPR06MB102eurprd_\"; type=\"multipart/alternative\""}, {:name=>"MIME-Version", :value=>"1.0"}, {:name=>"X-OriginatorOrg", :value=>"esnumerique.com"}, {:name=>"X-MS-Exchange-CrossTenant-originalarrivaltime", :value=>"14 Jan 2015 16:41:13.6540 (UTC)"}, {:name=>"X-MS-Exchange-CrossTenant-fromentityheader", :value=>"Hosted"}, {:name=>"X-MS-Exchange-CrossTenant-id", :value=>"8d916988-dc6a-4604-9152-c47698104d7b"}, {:name=>"X-MS-Exchange-Transport-CrossTenantHeadersStamped", :value=>"DB3PR06MB0937"}], :body=>{:size=>0}, :parts=>[{:mimeType=>"multipart/alternative", :filename=>"", :headers=>[{:name=>"Content-Type", :value=>"multipart/alternative; boundary=\"_000_AMSPR06MB102CF5CA6B835FEA9E50E6D97410AMSPR06MB102eurprd_\""}], :body=>{:size=>0}, :parts=>[{:partId=>"0.0", :mimeType=>"text/plain", :filename=>"", :headers=>[{:name=>"Content-Type", :value=>"text/plain; charset=\"utf-8\""}, {:name=>"Content-Transfer-Encoding", :value=>"base64"}], :body=>{:size=>1223, :data=>"Qm9uam91ciBKdWxpZSwNCg0KTGUgcGx1cyB0w7R0IHNlcmEgbGUgbWlldXgsIGrigJlhaSBow6J0ZSAhDQoNCkplIGJsb3F1ZSBsZSAxMi8wMg0KDQpNZXJjaQ0KDQpEZSA6IEp1bGllIERlc2sgW21haWx0bzpqdWxpZUBqdWxpZWRlc2suY29tXQ0KRW52b3nDqSA6IG1lcmNyZWRpIDE0IGphbnZpZXIgMjAxNSAxNzozOQ0Kw4AgOiBWaW5jZW50IEtsaW5nYmVpbA0KQ2MgOiBTYW5kcmEgUGVyZXoNCk9iamV0IDogUmU6IERlag0KDQpCb25qb3VyIFNhbmRyYSwNCg0KVmluY2VudCBlc3QgZGlzcG9uaWJsZSBwb3VyIGTDqWpldW5lciBhdmVjIHZvdXMgYXV4IGhvcmFpcmVzIHN1aXZhbnRzIDoNCg0KLSBKZXVkaSAxMiBGw6l2cmllciDDoCAxMjozMA0KLSBWZW5kcmVkaSAxMyBGw6l2cmllciDDoCAxMjozMA0KLSBMdW5kaSAxNiBGw6l2cmllciDDoCAxMjozMA0KLSBNZXJjcmVkaSAxOCBGw6l2cmllciDDoCAxMjozMA0KDQoNClF1ZWwgaG9yYWlyZSB2b3VzIGNvbnZpZW50IGxlIG1pZXV4ID8NCltodHRwczovL21haWxmb29nYWUuYXBwc3BvdC5jb20vdD9zZW5kZXI9YWFuVnNhV1ZBYW5Wc2FXVmtaWE5yTG1OdmJRJTNEJTNEJnR5cGU9emVyb2NvbnRlbnQmZ3VpZD02NDcxZGFjYS0wODYwLTQ3YWEtYTlkZS1iYjI5MzFlOTUxMWZd4ZCnDQoNCkNvcmRpYWxlbWVudCwNCg0KSnVsaWUNCg0KMjAxNS0wMS0xNCAxNzoyOCBHTVQrMDE6MDAgVmluY2VudCBLbGluZ2JlaWwgPHZpbmNlbnRrbGluZ2JlaWxAYW1ldGl4LmNvbTxtYWlsdG86dmluY2VudGtsaW5nYmVpbEBhbWV0aXguY29tPj46DQpIZWxsbyBTYW5kcmEsDQoNCkp1bGllIChlbiBjYykgdmEgdGUgcHJvcG9zZXIgZGVzIGRpc3BvcyBwb3VyIHVuIGRlai4NCg0KQSB0csOocyBiaWVudMO0dCwNCg0KDQoNCi0tLQ0KDQpWaW5jZW50IEtMSU5HQkVJTCAgW2NpZDppbWFnZTAwMy5qcGdAMDFDRjFEQjIuQkZCMTVEOTBdICBEaXJlY3RldXIgQXNzb2Npw6kNCjExLCBydWUgUm91Z2Vtb250IC0gNzUwMDkgUGFyaXMNClRlbCAgIDogMDEgODQgMTYgMTYgNTUNCk1vYiA6IDA2IDIyIDcyIDgzIDE3DQpFLW1haWwgOiB2aW5jZW50LmtsaW5nYmVpbEBhbWV0aXguY29tPG1haWx0bzp2aW5jZW50LmtsaW5nYmVpbEBhbWV0aXguY29tPg0KU2l0ZSA6IGh0dHA6Ly93d3cuYW1ldGl4LmNvbTxodHRwOi8vd3d3LmFtZXRpeC5jb20vPg0KDQpbY2lkOmltYWdlMDA0LnBuZ0AwMUNGMURCMi5CRkIxNUQ5MF0NCg0KDQo="}}, {:partId=>"0.1", :mimeType=>"text/html", :filename=>"", :headers=>[{:name=>"Content-Type", :value=>"text/html; charset=\"utf-8\""}, {:name=>"Content-Transfer-Encoding", :value=>"base64"}], :body=>{:size=>8246, :data=>"PGh0bWwgeG1sbnM6dj0idXJuOnNjaGVtYXMtbWljcm9zb2Z0LWNvbTp2bWwiIHhtbG5zOm89InVybjpzY2hlbWFzLW1pY3Jvc29mdC1jb206b2ZmaWNlOm9mZmljZSIgeG1sbnM6dz0idXJuOnNjaGVtYXMtbWljcm9zb2Z0LWNvbTpvZmZpY2U6d29yZCIgeG1sbnM6bT0iaHR0cDovL3NjaGVtYXMubWljcm9zb2Z0LmNvbS9vZmZpY2UvMjAwNC8xMi9vbW1sIiB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvVFIvUkVDLWh0bWw0MCI-DQo8aGVhZD4NCjxtZXRhIGh0dHAtZXF1aXY9IkNvbnRlbnQtVHlwZSIgY29udGVudD0idGV4dC9odG1sOyBjaGFyc2V0PXV0Zi04Ij4NCjxtZXRhIG5hbWU9IkdlbmVyYXRvciIgY29udGVudD0iTWljcm9zb2Z0IFdvcmQgMTUgKGZpbHRlcmVkIG1lZGl1bSkiPg0KPCEtLVtpZiAhbXNvXT48c3R5bGU-dlw6KiB7YmVoYXZpb3I6dXJsKCNkZWZhdWx0I1ZNTCk7fQ0Kb1w6KiB7YmVoYXZpb3I6dXJsKCNkZWZhdWx0I1ZNTCk7fQ0Kd1w6KiB7YmVoYXZpb3I6dXJsKCNkZWZhdWx0I1ZNTCk7fQ0KLnNoYXBlIHtiZWhhdmlvcjp1cmwoI2RlZmF1bHQjVk1MKTt9DQo8L3N0eWxlPjwhW2VuZGlmXS0tPjxzdHlsZT48IS0tDQovKiBGb250IERlZmluaXRpb25zICovDQpAZm9udC1mYWNlDQoJe2ZvbnQtZmFtaWx5OiJDYW1icmlhIE1hdGgiOw0KCXBhbm9zZS0xOjIgNCA1IDMgNSA0IDYgMyAyIDQ7fQ0KQGZvbnQtZmFjZQ0KCXtmb250LWZhbWlseTpDYWxpYnJpOw0KCXBhbm9zZS0xOjIgMTUgNSAyIDIgMiA0IDMgMiA0O30NCkBmb250LWZhY2UNCgl7Zm9udC1mYW1pbHk6R2FkdWdpOw0KCXBhbm9zZS0xOjIgMTEgNSAyIDQgMiA0IDIgMiAzO30NCi8qIFN0eWxlIERlZmluaXRpb25zICovDQpwLk1zb05vcm1hbCwgbGkuTXNvTm9ybWFsLCBkaXYuTXNvTm9ybWFsDQoJe21hcmdpbjowY207DQoJbWFyZ2luLWJvdHRvbTouMDAwMXB0Ow0KCWZvbnQtc2l6ZToxMi4wcHQ7DQoJZm9udC1mYW1pbHk6IlRpbWVzIE5ldyBSb21hbiIsc2VyaWY7fQ0KYTpsaW5rLCBzcGFuLk1zb0h5cGVybGluaw0KCXttc28tc3R5bGUtcHJpb3JpdHk6OTk7DQoJY29sb3I6Ymx1ZTsNCgl0ZXh0LWRlY29yYXRpb246dW5kZXJsaW5lO30NCmE6dmlzaXRlZCwgc3Bhbi5Nc29IeXBlcmxpbmtGb2xsb3dlZA0KCXttc28tc3R5bGUtcHJpb3JpdHk6OTk7DQoJY29sb3I6cHVycGxlOw0KCXRleHQtZGVjb3JhdGlvbjp1bmRlcmxpbmU7fQ0Kc3Bhbi5FbWFpbFN0eWxlMTcNCgl7bXNvLXN0eWxlLXR5cGU6cGVyc29uYWwtcmVwbHk7DQoJZm9udC1mYW1pbHk6IkNhbGlicmkiLHNhbnMtc2VyaWY7DQoJY29sb3I6IzFGNDk3RDt9DQouTXNvQ2hwRGVmYXVsdA0KCXttc28tc3R5bGUtdHlwZTpleHBvcnQtb25seTsNCglmb250LWZhbWlseToiQ2FsaWJyaSIsc2Fucy1zZXJpZjsNCgltc28tZmFyZWFzdC1sYW5ndWFnZTpFTi1VUzt9DQpAcGFnZSBXb3JkU2VjdGlvbjENCgl7c2l6ZTo2MTIuMHB0IDc5Mi4wcHQ7DQoJbWFyZ2luOjcwLjg1cHQgNzAuODVwdCA3MC44NXB0IDcwLjg1cHQ7fQ0KZGl2LldvcmRTZWN0aW9uMQ0KCXtwYWdlOldvcmRTZWN0aW9uMTt9DQotLT48L3N0eWxlPjwhLS1baWYgZ3RlIG1zbyA5XT48eG1sPg0KPG86c2hhcGVkZWZhdWx0cyB2OmV4dD0iZWRpdCIgc3BpZG1heD0iMTAyNiIgLz4NCjwveG1sPjwhW2VuZGlmXS0tPjwhLS1baWYgZ3RlIG1zbyA5XT48eG1sPg0KPG86c2hhcGVsYXlvdXQgdjpleHQ9ImVkaXQiPg0KPG86aWRtYXAgdjpleHQ9ImVkaXQiIGRhdGE9IjEiIC8-DQo8L286c2hhcGVsYXlvdXQ-PC94bWw-PCFbZW5kaWZdLS0-DQo8L2hlYWQ-DQo8Ym9keSBsYW5nPSJGUiIgbGluaz0iYmx1ZSIgdmxpbms9InB1cnBsZSI-DQo8ZGl2IGNsYXNzPSJXb3JkU2VjdGlvbjEiPg0KPHAgY2xhc3M9Ik1zb05vcm1hbCI-PHNwYW4gc3R5bGU9ImZvbnQtc2l6ZToxMS4wcHQ7Zm9udC1mYW1pbHk6JnF1b3Q7Q2FsaWJyaSZxdW90OyxzYW5zLXNlcmlmO2NvbG9yOiMxRjQ5N0Q7bXNvLWZhcmVhc3QtbGFuZ3VhZ2U6RU4tVVMiPkJvbmpvdXIgSnVsaWUsDQo8bzpwPjwvbzpwPjwvc3Bhbj48L3A-DQo8cCBjbGFzcz0iTXNvTm9ybWFsIj48c3BhbiBzdHlsZT0iZm9udC1zaXplOjExLjBwdDtmb250LWZhbWlseTomcXVvdDtDYWxpYnJpJnF1b3Q7LHNhbnMtc2VyaWY7Y29sb3I6IzFGNDk3RDttc28tZmFyZWFzdC1sYW5ndWFnZTpFTi1VUyI-PG86cD4mbmJzcDs8L286cD48L3NwYW4-PC9wPg0KPHAgY2xhc3M9Ik1zb05vcm1hbCI-PHNwYW4gc3R5bGU9ImZvbnQtc2l6ZToxMS4wcHQ7Zm9udC1mYW1pbHk6JnF1b3Q7Q2FsaWJyaSZxdW90OyxzYW5zLXNlcmlmO2NvbG9yOiMxRjQ5N0Q7bXNvLWZhcmVhc3QtbGFuZ3VhZ2U6RU4tVVMiPkxlIHBsdXMgdMO0dCBzZXJhIGxlIG1pZXV4LCBq4oCZYWkgaMOidGUmbmJzcDshDQo8bzpwPjwvbzpwPjwvc3Bhbj48L3A-DQo8cCBjbGFzcz0iTXNvTm9ybWFsIj48c3BhbiBzdHlsZT0iZm9udC1zaXplOjExLjBwdDtmb250LWZhbWlseTomcXVvdDtDYWxpYnJpJnF1b3Q7LHNhbnMtc2VyaWY7Y29sb3I6IzFGNDk3RDttc28tZmFyZWFzdC1sYW5ndWFnZTpFTi1VUyI-PG86cD4mbmJzcDs8L286cD48L3NwYW4-PC9wPg0KPHAgY2xhc3M9Ik1zb05vcm1hbCI-PHNwYW4gc3R5bGU9ImZvbnQtc2l6ZToxMS4wcHQ7Zm9udC1mYW1pbHk6JnF1b3Q7Q2FsaWJyaSZxdW90OyxzYW5zLXNlcmlmO2NvbG9yOiMxRjQ5N0Q7bXNvLWZhcmVhc3QtbGFuZ3VhZ2U6RU4tVVMiPkplIGJsb3F1ZSBsZSAxMi8wMjxvOnA-PC9vOnA-PC9zcGFuPjwvcD4NCjxwIGNsYXNzPSJNc29Ob3JtYWwiPjxzcGFuIHN0eWxlPSJmb250LXNpemU6MTEuMHB0O2ZvbnQtZmFtaWx5OiZxdW90O0NhbGlicmkmcXVvdDssc2Fucy1zZXJpZjtjb2xvcjojMUY0OTdEO21zby1mYXJlYXN0LWxhbmd1YWdlOkVOLVVTIj48bzpwPiZuYnNwOzwvbzpwPjwvc3Bhbj48L3A-DQo8cCBjbGFzcz0iTXNvTm9ybWFsIj48c3BhbiBzdHlsZT0iZm9udC1zaXplOjExLjBwdDtmb250LWZhbWlseTomcXVvdDtDYWxpYnJpJnF1b3Q7LHNhbnMtc2VyaWY7Y29sb3I6IzFGNDk3RDttc28tZmFyZWFzdC1sYW5ndWFnZTpFTi1VUyI-TWVyY2k8bzpwPjwvbzpwPjwvc3Bhbj48L3A-DQo8cCBjbGFzcz0iTXNvTm9ybWFsIj48c3BhbiBzdHlsZT0iZm9udC1zaXplOjExLjBwdDtmb250LWZhbWlseTomcXVvdDtDYWxpYnJpJnF1b3Q7LHNhbnMtc2VyaWY7Y29sb3I6IzFGNDk3RDttc28tZmFyZWFzdC1sYW5ndWFnZTpFTi1VUyI-PG86cD4mbmJzcDs8L286cD48L3NwYW4-PC9wPg0KPHAgY2xhc3M9Ik1zb05vcm1hbCI-PGI-PHNwYW4gc3R5bGU9ImZvbnQtc2l6ZToxMS4wcHQ7Zm9udC1mYW1pbHk6JnF1b3Q7Q2FsaWJyaSZxdW90OyxzYW5zLXNlcmlmIj5EZSZuYnNwOzo8L3NwYW4-PC9iPjxzcGFuIHN0eWxlPSJmb250LXNpemU6MTEuMHB0O2ZvbnQtZmFtaWx5OiZxdW90O0NhbGlicmkmcXVvdDssc2Fucy1zZXJpZiI-IEp1bGllIERlc2sgW21haWx0bzpqdWxpZUBqdWxpZWRlc2suY29tXQ0KPGJyPg0KPGI-RW52b3nDqSZuYnNwOzo8L2I-IG1lcmNyZWRpIDE0IGphbnZpZXIgMjAxNSAxNzozOTxicj4NCjxiPsOAJm5ic3A7OjwvYj4gVmluY2VudCBLbGluZ2JlaWw8YnI-DQo8Yj5DYyZuYnNwOzo8L2I-IFNhbmRyYSBQZXJlejxicj4NCjxiPk9iamV0Jm5ic3A7OjwvYj4gUmU6IERlajxvOnA-PC9vOnA-PC9zcGFuPjwvcD4NCjxwIGNsYXNzPSJNc29Ob3JtYWwiPjxvOnA-Jm5ic3A7PC9vOnA-PC9wPg0KPGRpdj4NCjxkaXY-DQo8cCBjbGFzcz0iTXNvTm9ybWFsIj5Cb25qb3VyIFNhbmRyYSw8YnI-DQo8YnI-DQpWaW5jZW50IGVzdCBkaXNwb25pYmxlIHBvdXIgZMOpamV1bmVyIGF2ZWMgdm91cyBhdXggaG9yYWlyZXMgc3VpdmFudHMgOjxicj4NCjxicj4NCi0gSmV1ZGkgMTIgRsOpdnJpZXIgw6AgMTI6MzA8YnI-DQotIFZlbmRyZWRpIDEzIEbDqXZyaWVyIMOgIDEyOjMwPGJyPg0KLSBMdW5kaSAxNiBGw6l2cmllciDDoCAxMjozMDxicj4NCi0gTWVyY3JlZGkgMTggRsOpdnJpZXIgw6AgMTI6MzA8YnI-DQo8YnI-DQo8YnI-DQpRdWVsIGhvcmFpcmUgdm91cyBjb252aWVudCBsZSBtaWV1eCA_PG86cD48L286cD48L3A-DQo8L2Rpdj4NCjxkaXY-DQo8cCBjbGFzcz0iTXNvTm9ybWFsIj48aW1nIGlkPSJfeDAwMDBfaTEwMjUiIHNyYz0iaHR0cHM6Ly9tYWlsZm9vZ2FlLmFwcHNwb3QuY29tL3Q_c2VuZGVyPWFhblZzYVdWQWFuVnNhV1ZrWlhOckxtTnZiUSUzRCUzRCZhbXA7dHlwZT16ZXJvY29udGVudCZhbXA7Z3VpZD02NDcxZGFjYS0wODYwLTQ3YWEtYTlkZS1iYjI5MzFlOTUxMWYiPjxzcGFuIHN0eWxlPSJmb250LXNpemU6Ny41cHQ7Zm9udC1mYW1pbHk6JnF1b3Q7R2FkdWdpJnF1b3Q7LHNhbnMtc2VyaWY7Y29sb3I6d2hpdGUiPuGQpzwvc3Bhbj48bzpwPjwvbzpwPjwvcD4NCjwvZGl2Pg0KPC9kaXY-DQo8ZGl2Pg0KPHAgY2xhc3M9Ik1zb05vcm1hbCI-PGJyIGNsZWFyPSJhbGwiPg0KPG86cD48L286cD48L3A-DQo8ZGl2Pg0KPGRpdj4NCjxkaXY-DQo8cCBjbGFzcz0iTXNvTm9ybWFsIj5Db3JkaWFsZW1lbnQsPG86cD48L286cD48L3A-DQo8ZGl2Pg0KPHAgY2xhc3M9Ik1zb05vcm1hbCI-PG86cD4mbmJzcDs8L286cD48L3A-DQo8L2Rpdj4NCjxkaXY-DQo8cCBjbGFzcz0iTXNvTm9ybWFsIj5KdWxpZTxvOnA-PC9vOnA-PC9wPg0KPC9kaXY-DQo8L2Rpdj4NCjwvZGl2Pg0KPC9kaXY-DQo8cCBjbGFzcz0iTXNvTm9ybWFsIj48bzpwPiZuYnNwOzwvbzpwPjwvcD4NCjxkaXY-DQo8cCBjbGFzcz0iTXNvTm9ybWFsIj4yMDE1LTAxLTE0IDE3OjI4IEdNVCYjNDM7MDE6MDAgVmluY2VudCBLbGluZ2JlaWwgJmx0OzxhIGhyZWY9Im1haWx0bzp2aW5jZW50a2xpbmdiZWlsQGFtZXRpeC5jb20iIHRhcmdldD0iX2JsYW5rIj52aW5jZW50a2xpbmdiZWlsQGFtZXRpeC5jb208L2E-Jmd0Ozo8bzpwPjwvbzpwPjwvcD4NCjxibG9ja3F1b3RlIHN0eWxlPSJib3JkZXI6bm9uZTtib3JkZXItbGVmdDpzb2xpZCAjQ0NDQ0NDIDEuMHB0O3BhZGRpbmc6MGNtIDBjbSAwY20gNi4wcHQ7bWFyZ2luLWxlZnQ6NC44cHQ7bWFyZ2luLXJpZ2h0OjBjbSI-DQo8ZGl2Pg0KPGRpdj4NCjxwIGNsYXNzPSJNc29Ob3JtYWwiIHN0eWxlPSJtc28tbWFyZ2luLXRvcC1hbHQ6YXV0bzttc28tbWFyZ2luLWJvdHRvbS1hbHQ6YXV0byI-SGVsbG8gU2FuZHJhLDxvOnA-PC9vOnA-PC9wPg0KPHAgY2xhc3M9Ik1zb05vcm1hbCIgc3R5bGU9Im1zby1tYXJnaW4tdG9wLWFsdDphdXRvO21zby1tYXJnaW4tYm90dG9tLWFsdDphdXRvIj4mbmJzcDs8bzpwPjwvbzpwPjwvcD4NCjxwIGNsYXNzPSJNc29Ob3JtYWwiIHN0eWxlPSJtc28tbWFyZ2luLXRvcC1hbHQ6YXV0bzttc28tbWFyZ2luLWJvdHRvbS1hbHQ6YXV0byI-SnVsaWUgKGVuIGNjKSB2YSB0ZSBwcm9wb3NlciBkZXMgZGlzcG9zIHBvdXIgdW4gZGVqLjxvOnA-PC9vOnA-PC9wPg0KPHAgY2xhc3M9Ik1zb05vcm1hbCIgc3R5bGU9Im1zby1tYXJnaW4tdG9wLWFsdDphdXRvO21zby1tYXJnaW4tYm90dG9tLWFsdDphdXRvIj48YnI-DQpBIHRyw6hzIGJpZW50w7R0LDxvOnA-PC9vOnA-PC9wPg0KPHAgY2xhc3M9Ik1zb05vcm1hbCIgc3R5bGU9Im1zby1tYXJnaW4tdG9wLWFsdDphdXRvO21zby1tYXJnaW4tYm90dG9tLWFsdDphdXRvIj4mbmJzcDs8bzpwPjwvbzpwPjwvcD4NCjxwIGNsYXNzPSJNc29Ob3JtYWwiIHN0eWxlPSJtc28tbWFyZ2luLXRvcC1hbHQ6YXV0bzttc28tbWFyZ2luLWJvdHRvbS1hbHQ6YXV0byI-Jm5ic3A7PG86cD48L286cD48L3A-DQo8cCBjbGFzcz0iTXNvTm9ybWFsIiBzdHlsZT0ibXNvLW1hcmdpbi10b3AtYWx0OmF1dG87bXNvLW1hcmdpbi1ib3R0b20tYWx0OmF1dG8iPiZuYnNwOzxvOnA-PC9vOnA-PC9wPg0KPHAgY2xhc3M9Ik1zb05vcm1hbCIgc3R5bGU9Im1zby1tYXJnaW4tdG9wLWFsdDphdXRvO21zby1tYXJnaW4tYm90dG9tLWFsdDphdXRvO2JhY2tncm91bmQ6d2hpdGUiPg0KPGI-PHNwYW4gc3R5bGU9ImZvbnQtc2l6ZToxMC4wcHQ7Y29sb3I6IzVFNUU1RSI-LS0tPC9zcGFuPjwvYj48bzpwPjwvbzpwPjwvcD4NCjxwIGNsYXNzPSJNc29Ob3JtYWwiIHN0eWxlPSJtc28tbWFyZ2luLXRvcC1hbHQ6YXV0bzttc28tbWFyZ2luLWJvdHRvbS1hbHQ6YXV0bztiYWNrZ3JvdW5kOndoaXRlIj4NCjxiPjxzcGFuIHN0eWxlPSJmb250LXNpemU6MTAuMHB0O2NvbG9yOiM1RTVFNUUiPiZuYnNwOzwvc3Bhbj48L2I-PG86cD48L286cD48L3A-DQo8cCBjbGFzcz0iTXNvTm9ybWFsIiBzdHlsZT0ibXNvLW1hcmdpbi10b3AtYWx0OmF1dG87bXNvLW1hcmdpbi1ib3R0b20tYWx0OmF1dG87YmFja2dyb3VuZDp3aGl0ZSI-DQo8Yj48c3BhbiBzdHlsZT0iZm9udC1zaXplOjEwLjBwdDtjb2xvcjojNUU1RTVFIj5WaW5jZW50IEtMSU5HQkVJTCAmbmJzcDs8aW1nIGJvcmRlcj0iMCIgd2lkdGg9IjE3IiBoZWlnaHQ9IjE3IiBpZD0iX3gwMDAwX2kxMDI2IiBzcmM9ImNpZDppbWFnZTAwMS5qcGdAMDFEMDMwMjAuQTgxRDNFQzAiIGFsdD0iY2lkOmltYWdlMDAzLmpwZ0AwMUNGMURCMi5CRkIxNUQ5MCI-IERpcmVjdGV1ciBBc3NvY2nDqTwvc3Bhbj48L2I-PG86cD48L286cD48L3A-DQo8cCBjbGFzcz0iTXNvTm9ybWFsIiBzdHlsZT0ibXNvLW1hcmdpbi10b3AtYWx0OmF1dG87bXNvLW1hcmdpbi1ib3R0b20tYWx0OmF1dG87YmFja2dyb3VuZDp3aGl0ZSI-DQo8c3BhbiBzdHlsZT0iZm9udC1zaXplOjkuMHB0O2NvbG9yOiM1RTVFNUUiPjExLCBydWUgUm91Z2Vtb250IC0gNzUwMDkgUGFyaXM8L3NwYW4-PHNwYW4gc3R5bGU9ImZvbnQtc2l6ZToxMC4wcHQ7Y29sb3I6YmxhY2siPjxicj4NCjwvc3Bhbj48c3BhbiBzdHlsZT0iZm9udC1zaXplOjkuMHB0O2NvbG9yOiM1RTVFNUUiPlRlbCZuYnNwOyAmbmJzcDs6IDAxIDg0IDE2IDE2IDU1PC9zcGFuPjxvOnA-PC9vOnA-PC9wPg0KPHAgY2xhc3M9Ik1zb05vcm1hbCIgc3R5bGU9Im1zby1tYXJnaW4tdG9wLWFsdDphdXRvO21zby1tYXJnaW4tYm90dG9tLWFsdDphdXRvO2JhY2tncm91bmQ6d2hpdGUiPg0KPHNwYW4gc3R5bGU9ImZvbnQtc2l6ZTo5LjBwdDtjb2xvcjojNUU1RTVFIj5Nb2IgOiAwNiAyMiA3MiA4MyAxNzxicj4NCkUtbWFpbCA6IDwvc3Bhbj48c3BhbiBzdHlsZT0iZm9udC1zaXplOjkuMHB0O2NvbG9yOiM1QjlCRDUiPjxhIGhyZWY9Im1haWx0bzp2aW5jZW50LmtsaW5nYmVpbEBhbWV0aXguY29tIiB0YXJnZXQ9Il9ibGFuayI-PHNwYW4gc3R5bGU9ImNvbG9yOiM1QjlCRDUiPnZpbmNlbnQua2xpbmdiZWlsQGFtZXRpeC5jb208L3NwYW4-PC9hPg0KPC9zcGFuPjxvOnA-PC9vOnA-PC9wPg0KPHAgY2xhc3M9Ik1zb05vcm1hbCIgc3R5bGU9Im1zby1tYXJnaW4tdG9wLWFsdDphdXRvO21zby1tYXJnaW4tYm90dG9tLWFsdDphdXRvO2JhY2tncm91bmQ6d2hpdGUiPg0KPHNwYW4gc3R5bGU9ImZvbnQtc2l6ZTo5LjBwdDtjb2xvcjojNUU1RTVFIj5TaXRlIDogPC9zcGFuPjxzcGFuIHN0eWxlPSJmb250LXNpemU6OS4wcHQ7Y29sb3I6IzVCOUJENSI-PGEgaHJlZj0iaHR0cDovL3d3dy5hbWV0aXguY29tLyIgdGFyZ2V0PSJfYmxhbmsiPjxzcGFuIHN0eWxlPSJjb2xvcjojNUI5QkQ1Ij5odHRwOi8vd3d3LmFtZXRpeC5jb208L3NwYW4-PC9hPg0KPC9zcGFuPjxvOnA-PC9vOnA-PC9wPg0KPHAgY2xhc3M9Ik1zb05vcm1hbCIgc3R5bGU9Im1zby1tYXJnaW4tdG9wLWFsdDphdXRvO21zby1tYXJnaW4tYm90dG9tLWFsdDphdXRvIj4mbmJzcDs8bzpwPjwvbzpwPjwvcD4NCjxwIGNsYXNzPSJNc29Ob3JtYWwiIHN0eWxlPSJtc28tbWFyZ2luLXRvcC1hbHQ6YXV0bzttc28tbWFyZ2luLWJvdHRvbS1hbHQ6YXV0byI-PHNwYW4gc3R5bGU9ImZvbnQtc2l6ZToxMC41cHQ7Y29sb3I6YmxhY2siPjxpbWcgYm9yZGVyPSIwIiB3aWR0aD0iMjM2IiBoZWlnaHQ9IjEwNCIgaWQ9Il94MDAwMF9pMTAyNyIgc3JjPSJjaWQ6aW1hZ2UwMDIucG5nQDAxRDAzMDIwLkE4MUQzRUMwIiBhbHQ9ImNpZDppbWFnZTAwNC5wbmdAMDFDRjFEQjIuQkZCMTVEOTAiPjwvc3Bhbj48bzpwPjwvbzpwPjwvcD4NCjxwIGNsYXNzPSJNc29Ob3JtYWwiIHN0eWxlPSJtc28tbWFyZ2luLXRvcC1hbHQ6YXV0bzttc28tbWFyZ2luLWJvdHRvbS1hbHQ6YXV0byI-Jm5ic3A7PG86cD48L286cD48L3A-DQo8L2Rpdj4NCjwvZGl2Pg0KPC9ibG9ja3F1b3RlPg0KPC9kaXY-DQo8cCBjbGFzcz0iTXNvTm9ybWFsIj48bzpwPiZuYnNwOzwvbzpwPjwvcD4NCjwvZGl2Pg0KPC9kaXY-DQo8L2JvZHk-DQo8L2h0bWw-DQo="}}]}, {:partId=>"1", :mimeType=>"image/jpeg", :filename=>"image001.jpg", :headers=>[{:name=>"Content-Type", :value=>"image/jpeg; name=\"image001.jpg\""}, {:name=>"Content-Description", :value=>"image001.jpg"}, {:name=>"Content-Disposition", :value=>"inline; filename=\"image001.jpg\"; size=745; creation-date=\"Wed, 14 Jan 2015 16:41:12 GMT\"; modification-date=\"Wed, 14 Jan 2015 16:41:12 GMT\""}, {:name=>"Content-ID", :value=>""}, {:name=>"Content-Transfer-Encoding", :value=>"base64"}], :body=>{:attachmentId=>"ANGjdJ9EUce9luxTns6YCguM66uWOxWwYQvDeG0x_b--7WtuX286rMcFGJCzxreUbo81SqPcPmi_SH4Pwj5n6OhAGDh1U2vogEB2JE13baFrUObxecXTeaaO6jeq78j7dv6ZtY0ivtRdQQKFDddIctZ2xDYJ7YuMNm1LDpuWGR5f_yNIDL-9t5EQY8FWEGhcXAZOS_JSxqc5v469Mxt9bRK6-r-8I7p6C9kEtxm6s1DMpEMaV0veKGU7Fcu7kpO7_6xoCc16fMGDWnlX5tmRv1KGopc9E5WQoq453aFAig", :size=>1024}}, {:partId=>"2", :mimeType=>"image/png", :filename=>"image002.png", :headers=>[{:name=>"Content-Type", :value=>"image/png; name=\"image002.png\""}, {:name=>"Content-Description", :value=>"image002.png"}, {:name=>"Content-Disposition", :value=>"inline; filename=\"image002.png\"; size=18240; creation-date=\"Wed, 14 Jan 2015 16:41:13 GMT\"; modification-date=\"Wed, 14 Jan 2015 16:41:13 GMT\""}, {:name=>"Content-ID", :value=>""}, {:name=>"Content-Transfer-Encoding", :value=>"base64"}], :body=>{:attachmentId=>"ANGjdJ9ZpRLg9NX7RpBGCcmbfrARNV5R3BJLY2O5jKfpgfpe1rntEYXw0Vr0bIYMMU9DJ3jc-ofm2NNsKeu5wkjB3IglrGe19BHrgjWh9Mz_65H-Lp3x_avlwVg4Tm1lmyWF6POmK5BN64vlwQGcSJbaytrRI6PuRVeLLBWI32xfllZi-N_Pf9JNPgNouf_jVP8XFzl9pPD6gIaUugsMNdUXPEyx0pY00JOhgkP1P0Wcz6EU931R9Au19mYdO87ROzdBAea7ekqA3xHT5E7XpnC5O9XyJAray1D9iPWVcQ", :size=>24960}}]}, :sizeEstimate=>44153}
23 | end
24 |
25 | def test_draft_list(params={})
26 | {:drafts=>[{:id=>"1490204870554280932", :message=>{:id=>"14ae456f2ff1e3e4", :threadId=>"14ae456f2ff1e3e4"}}, {:id=>"1490204870554280939", :message=>{:id=>"14ae456f2ff1e3e5", :threadId=>"14ae456f2ff1e3e5"}}], :resultSizeEstimate=>2}.merge(params)
27 | end
28 |
29 | def test_label params={}
30 | {
31 | :id=>"CATEGORY_UPDATES",
32 | :name=>"CATEGORY_UPDATES",
33 | :messageListVisibility=>"hide",
34 | :labelListVisibility=>"labelHide",
35 | :type=>"system",
36 | :messagesTotal=>129,
37 | :messagesUnread=>33,
38 | :threadsTotal=>105,
39 | :threadsUnread=>21
40 | }.merge(params)
41 | end
42 |
43 | def test_label_list(params={})
44 | {:labels=>[{:id=>"CATEGORY_UPDATES", :name=>"CATEGORY_UPDATES", :messageListVisibility=>"hide", :labelListVisibility=>"labelHide", :type=>"system"}, {:id=>"UNREAD", :name=>"UNREAD", :type=>"system"}, {:id=>"DRAFT", :name=>"DRAFT", :messageListVisibility=>"hide", :labelListVisibility=>"labelShow", :type=>"system"}, {:id=>"INBOX", :name=>"INBOX", :messageListVisibility=>"hide", :labelListVisibility=>"labelShow", :type=>"system"}, {:id=>"CATEGORY_PROMOTIONS", :name=>"CATEGORY_PROMOTIONS", :messageListVisibility=>"hide", :labelListVisibility=>"labelHide", :type=>"system"}, {:id=>"CATEGORY_SOCIAL", :name=>"CATEGORY_SOCIAL", :messageListVisibility=>"hide", :labelListVisibility=>"labelHide", :type=>"system"}, {:id=>"CATEGORY_PERSONAL", :name=>"CATEGORY_PERSONAL", :messageListVisibility=>"hide", :labelListVisibility=>"labelHide", :type=>"system"}, {:id=>"CATEGORY_FORUMS", :name=>"CATEGORY_FORUMS", :messageListVisibility=>"hide", :labelListVisibility=>"labelHide", :type=>"system"}, {:id=>"TRASH", :name=>"TRASH", :messageListVisibility=>"hide", :labelListVisibility=>"labelHide", :type=>"system"}, {:id=>"IMPORTANT", :name=>"IMPORTANT", :messageListVisibility=>"hide", :labelListVisibility=>"labelHide", :type=>"system"}, {:id=>"SENT", :name=>"SENT", :messageListVisibility=>"hide", :labelListVisibility=>"labelShow", :type=>"system"}, {:id=>"STARRED", :name=>"STARRED", :messageListVisibility=>"hide", :labelListVisibility=>"labelShow", :type=>"system"}, {:id=>"SPAM", :name=>"SPAM", :messageListVisibility=>"hide", :labelListVisibility=>"labelHide", :type=>"system"}]}.merge(params)
45 | end
46 |
47 | def test_thread(params = {})
48 | {:id=>"14ae456f2ff1e3e4", :historyId=>"227960", :messages=>[
49 | {:id=>"14ae456f2ff1e3e4", :threadId=>"14ae456f2ff1e3e4", :labelIds=>["DRAFT"], :snippet=>"sd Cordialement, Julie", :historyId=>"227960", :payload=>{:mimeType=>"multipart/alternative", :filename=>"", :headers=>[{:name=>"MIME-Version", :value=>"1.0"}, {:name=>"Received", :value=>"by 10.64.21.4 with HTTP; Tue, 13 Jan 2015 09:28:31 -0800 (PST)"}, {:name=>"Date", :value=>"Tue, 13 Jan 2015 18:28:31 +0100"}, {:name=>"Message-ID", :value=>""}, {:name=>"Subject", :value=>""}, {:name=>"From", :value=>"Julie Desk "}, {:name=>"Content-Type", :value=>"multipart/alternative; boundary=f46d042abf34a36bd9050c8bf335"}], :body=>{:size=>0}, :parts=>[{:partId=>"0", :mimeType=>"text/plain", :filename=>"", :headers=>[{:name=>"Content-Type", :value=>"text/plain; charset=UTF-8"}], :body=>{:size=>28, :data=>"c2QNCkNvcmRpYWxlbWVudCwNCg0KSnVsaWUNCg=="}}, {:partId=>"1", :mimeType=>"text/html", :filename=>"", :headers=>[{:name=>"Content-Type", :value=>"text/html; charset=UTF-8"}], :body=>{:size=>154, :data=>"PGRpdiBkaXI9Imx0ciI-c2Q8YnIgY2xlYXI9ImFsbCI-PGRpdj48ZGl2IGNsYXNzPSJnbWFpbF9zaWduYXR1cmUiPjxkaXYgZGlyPSJsdHIiPkNvcmRpYWxlbWVudCw8ZGl2Pjxicj48L2Rpdj48ZGl2Pkp1bGllPC9kaXY-PC9kaXY-PC9kaXY-PC9kaXY-DQo8L2Rpdj4NCg=="}}]}, :sizeEstimate=>710},
50 | {:id=>"14ae456f2ff1e3e4", :threadId=>"14ae456f2ff1e3e4", :labelIds=>["SENT"], :snippet=>"sd Cordialement, Julie", :historyId=>"227960", :payload=>{:mimeType=>"multipart/alternative", :filename=>"", :headers=>[{:name=>"MIME-Version", :value=>"1.0"}, {:name=>"Received", :value=>"by 10.64.21.4 with HTTP; Tue, 13 Jan 2015 09:28:31 -0800 (PST)"}, {:name=>"Date", :value=>"Tue, 13 Jan 2015 18:28:31 +0100"}, {:name=>"Message-ID", :value=>""}, {:name=>"Subject", :value=>""}, {:name=>"From", :value=>"Julie Desk "}, {:name=>"Content-Type", :value=>"multipart/alternative; boundary=f46d042abf34a36bd9050c8bf335"}], :body=>{:size=>0}, :parts=>[{:partId=>"0", :mimeType=>"text/plain", :filename=>"", :headers=>[{:name=>"Content-Type", :value=>"text/plain; charset=UTF-8"}], :body=>{:size=>28, :data=>"c2QNCkNvcmRpYWxlbWVudCwNCg0KSnVsaWUNCg=="}}, {:partId=>"1", :mimeType=>"text/html", :filename=>"", :headers=>[{:name=>"Content-Type", :value=>"text/html; charset=UTF-8"}], :body=>{:size=>154, :data=>"PGRpdiBkaXI9Imx0ciI-c2Q8YnIgY2xlYXI9ImFsbCI-PGRpdj48ZGl2IGNsYXNzPSJnbWFpbF9zaWduYXR1cmUiPjxkaXYgZGlyPSJsdHIiPkNvcmRpYWxlbWVudCw8ZGl2Pjxicj48L2Rpdj48ZGl2Pkp1bGllPC9kaXY-PC9kaXY-PC9kaXY-PC9kaXY-DQo8L2Rpdj4NCg=="}}]}, :sizeEstimate=>710},
51 | {:id=>"14ae456f2ff1e3e4", :threadId=>"14ae456f2ff1e3e4", :labelIds=>["UNREAD"], :snippet=>"sd Cordialement, Julie", :historyId=>"227960", :payload=>{:mimeType=>"multipart/alternative", :filename=>"", :headers=>[{:name=>"MIME-Version", :value=>"1.0"}, {:name=>"Received", :value=>"by 10.64.21.4 with HTTP; Tue, 13 Jan 2015 09:28:31 -0800 (PST)"}, {:name=>"Date", :value=>"Tue, 13 Jan 2015 18:28:31 +0100"}, {:name=>"Message-ID", :value=>""}, {:name=>"Subject", :value=>""}, {:name=>"From", :value=>"Julie Desk "}, {:name=>"Content-Type", :value=>"multipart/alternative; boundary=f46d042abf34a36bd9050c8bf335"}], :body=>{:size=>0}, :parts=>[{:partId=>"0", :mimeType=>"text/plain", :filename=>"", :headers=>[{:name=>"Content-Type", :value=>"text/plain; charset=UTF-8"}], :body=>{:size=>28, :data=>"c2QNCkNvcmRpYWxlbWVudCwNCg0KSnVsaWUNCg=="}}, {:partId=>"1", :mimeType=>"text/html", :filename=>"", :headers=>[{:name=>"Content-Type", :value=>"text/html; charset=UTF-8"}], :body=>{:size=>154, :data=>"PGRpdiBkaXI9Imx0ciI-c2Q8YnIgY2xlYXI9ImFsbCI-PGRpdj48ZGl2IGNsYXNzPSJnbWFpbF9zaWduYXR1cmUiPjxkaXYgZGlyPSJsdHIiPkNvcmRpYWxlbWVudCw8ZGl2Pjxicj48L2Rpdj48ZGl2Pkp1bGllPC9kaXY-PC9kaXY-PC9kaXY-PC9kaXY-DQo8L2Rpdj4NCg=="}}]}, :sizeEstimate=>710},
52 |
53 | ]}.merge(params)
54 | end
55 |
56 | def test_thread_list
57 | {:threads=>[{:id=>"14ae456f2ff1e3e4", :snippet=>"", :historyId=>"227960"}, {:id=>"14ae4438ed604170", :snippet=>"", :historyId=>"227955"}, {:id=>"14ac91101e18bed8", :snippet=>"", :historyId=>"227646"}, {:id=>"14ae3d759a2166d1", :snippet=>"", :historyId=>"227565"}, {:id=>"14acfd71d2f20308", :snippet=>"", :historyId=>"227430"}], :nextPageToken=>"11260038910369504656", :resultSizeEstimate=>25}
58 | end
59 |
60 | def test_message(params = {})
61 | {:id=>"14ada61b92db5e63", :threadId=>"14ada58320652fc7", :labelIds=>["IMPORTANT", "CATEGORY_PERSONAL"], :snippet=>"Bonsoir David Merci pour votre retour. Je verrai demain avec Julie, quand fixer un RDV téléphonique.", :historyId=>"219674", :payload=>{:mimeType=>"multipart/alternative", :filename=>"", :headers=>[{:name=>"Delivered-To", :value=>"julie@juliedesk.com"}, {:name=>"Received", :value=>"by 10.64.89.39 with SMTP id bl7csp849585ieb; Sun, 11 Jan 2015 11:04:05 -0800 (PST)"}, {:name=>"X-Received", :value=>"by 10.180.75.237 with SMTP id f13mr23178958wiw.69.1421003044898; Sun, 11 Jan 2015 11:04:04 -0800 (PST)"}, {:name=>"Return-Path", :value=>""}, {:name=>"Received", :value=>"from mail-wg0-x232.google.com (mail-wg0-x232.google.com. [2a00:1450:400c:c00::232]) by mx.google.com with ESMTPS id o4si9737386wia.79.2015.01.11.11.04.04 for (version=TLSv1 cipher=ECDHE-RSA-RC4-SHA bits=128/128); Sun, 11 Jan 2015 11:04:04 -0800 (PST)"}, {:name=>"Received-SPF", :value=>"pass (google.com: domain of arlenebentolila@gmail.com designates 2a00:1450:400c:c00::232 as permitted sender) client-ip=2a00:1450:400c:c00::232;"}, {:name=>"Authentication-Results", :value=>"mx.google.com; spf=pass (google.com: domain of arlenebentolila@gmail.com designates 2a00:1450:400c:c00::232 as permitted sender) smtp.mail=arlenebentolila@gmail.com; dkim=pass header.i=@gmail.com; dmarc=pass (p=NONE dis=NONE) header.from=gmail.com"}, {:name=>"Received", :value=>"by mail-wg0-f50.google.com with SMTP id a1so15938647wgh.9 for ; Sun, 11 Jan 2015 11:04:04 -0800 (PST)"}, {:name=>"DKIM-Signature", :value=>"v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20120113; h=content-type:mime-version:subject:from:in-reply-to:date:cc :content-transfer-encoding:message-id:references:to; bh=mEmKhvWjFpq+DnO0xxdPjpd/i7MTfctQp+prGlYASc4=; b=ouf26RPtOvk9wATJjcDxdOET2WD58x6efOOd8sZXt9c09mCoAsocVHyihpWWacId9j qtuhKv/bTOe8AbMnk3JU4PHgnyJyCDL3gRjUrnlzMmwb92gd2c6TxS/p711fYvDfrz+L jyABwocRbJSBTH/YsGPh/sP/z89oE0Aox5QIvd7PE1ykUWIhk4GVhGx7qf/SEImA4oGB zb17MgSVHx7s9glVeibxturDZXJPSPS/sFX4VgHtMT4GlKvjtiLKJl3G+rIAbV+YsIet zmcrurpZM97/ztnL/8IrQG17Kqe+JqanNlVwvhEMfTLOxooC+5p1v1tdHvN+8RMAcYWv QyrQ=="}, {:name=>"X-Received", :value=>"by 10.194.175.102 with SMTP id bz6mr2702286wjc.120.1421003043927; Sun, 11 Jan 2015 11:04:03 -0800 (PST)"}, {:name=>"Return-Path", :value=>""}, {:name=>"Received", :value=>"from [192.168.0.39] (fes75-2-78-192-50-38.fbxo.proxad.net. [78.192.50.38]) by mx.google.com with ESMTPSA id i15sm18583199wjq.22.2015.01.11.11.04.02 (version=TLSv1 cipher=ECDHE-RSA-RC4-SHA bits=128/128); Sun, 11 Jan 2015 11:04:02 -0800 (PST)"}, {:name=>"Content-Type", :value=>"multipart/alternative; boundary=Apple-Mail-47C5C329-5673-4226-945A-D9F99028CBB5"}, {:name=>"Mime-Version", :value=>"1.0 (1.0)"}, {:name=>"Subject", :value=>"Re: Recommandation Sup de Luxe pour sujet de mémoire Arlène Bentolila"}, {:name=>"From", :value=>"\"Arlène Bentolila\" "}, {:name=>"X-Mailer", :value=>"iPhone Mail (12B440)"}, {:name=>"In-Reply-To", :value=>""}, {:name=>"Date", :value=>"Sun, 11 Jan 2015 20:04:01 +0100"}, {:name=>"Cc", :value=>"Julie Desk "}, {:name=>"Bcc", :value=>"Julien "}, {:name=>"Content-Transfer-Encoding", :value=>"7bit"}, {:name=>"Message-Id", :value=>""}, {:name=>"References", :value=>" "}, {:name=>"To", :value=>"David Alexandre Klingbeil "}], :body=>{:size=>0}, :parts=>[{:partId=>"0", :mimeType=>"text/plain", :filename=>"", :headers=>[{:name=>"Content-Type", :value=>"text/plain; charset=utf-8"}, {:name=>"Content-Transfer-Encoding", :value=>"quoted-printable"}], :body=>{:size=>6912, :data=>"Qm9uc29pciBEYXZpZA0KDQpNZXJjaSBwb3VyIHZvdHJlIHJldG91ci4gSmUgdmVycmFpIGRlbWFpbiBhdmVjIEp1bGllLCBxdWFuZCBmaXhlciB1biBSRFYgdMOpbMOpcGhvbmlxdWUuIA0KDQpQb3VyIGluZm9ybWF0aW9uLCBqJ2FpIGFqdXN0w6kgbW9uIHN1amV0IGRlIG3DqW1vaXJlIHF1ZSBqZSB0cm91dmFpcyB0cm9wIGNsYXNzaXF1ZSBldCBjZSwgYXByw6hzIGF2b2lyIMOpY2hhbmfDqSBhdmVjIGRlcyBjb25zdWx0YW50cy4gIA0KSmUgdm91cyBsJ2V4cG9zZSBjaS1kZXNzb3VzLiBWb3MgY29uc2VpbHMgZXQgcmVtYXJxdWVzIG1lIHNlcm9udCB0cmVzIHV0aWxlcy4gIA0KDQpTdWpldCAoZW52b3nDqSDDoCBTdXAgZGUgTHV4ZSBhdmFudCBoaWVyLCBWZW5kcmVkaSk6IA0KDQpDb21tZW50IGxlcyBtYXJxdWVzIGRlIG1vZGUgZXQgZGUgam9haWxsZXJpZSBzJ3kgcHJlbm5lbnQgcG91ciBhcHByw6loZW5kZXIgbGVzIG9iamV0cyBjb25uZWN0w6lzIGRhbnMgbGV1ciBzdHJhdMOpZ2llIGQnb2ZmcmU_IA0KSmUgdmV1eCBkw6ltb250cmVyIHF1ZSBsZXMgb2JqZXRzIGNvbm5lY3TDqXMgc29udCB1biBsZXZpZXIgZGUgY3JvaXNzYW5jZSBldCBkZSBkaWZmw6lyZW5jaWF0aW9uLiBKZSB2ZXV4IGFuYWx5c2VyIGxlcyBjb21wb3J0ZW1lbnRzIGRlcyBtYXJxdWVzIGZhY2Ugw6AgY2V0IGVuamV1eDogdm9udCAtIGVsbGVzIHJlc3TDqWVzIGRhbnMgbGUgY2xhc3NpY2lzbWUgYXZlYyBkZXMgbWF0acOocmVzIG5vYmxlcyBwYXIgZXhlbXBsZSBvdSDDqXZvbHVlciBkZSBmYcOnb24gc2lnbmlmaWNhdGl2ZXMgYXZlYyBsZXMgb2JqZXRzIGNvbm5lY3TDqXM_IENvbW1lbnQgYXBwcsOpaGVuZGVudCAtIGVsbGVzIGNlIGNoYW5nZW1lbnQgZGlnaXRhbCBkYW5zIGxldXIgc3RyYXTDqWdpZSBk4oCZb2ZmcmUgZXQgZGUgZMOpdmVsb3BwZW1lbnQ_DQoNCkJpZW4gw6Agdm91cyANCkFybMOobmUNCg0KQXJsw6huZSBCZW50b2xpbGENCkVudm95w6kgZGUgbW9uIGlQaG9uZS4NCjA2IDYyIDE4IDQ3IDA4DQoNCg0KPiBMZSAxMSBqYW52LiAyMDE1IMOgIDE5OjUzLCBEYXZpZCBBbGV4YW5kcmUgS2xpbmdiZWlsIDxkYWtAZHltYW50LmNvbT4gYSDDqWNyaXQgOg0KPiANCj4gQm9uc29pciBBcmxlbmUsDQo-IA0KPiBQYXJsb25zLWVuIHBhciB0w6lsw6lwaG9uZSBjZXR0ZSBzZW1haW5lIG91IGxhIHN1aXZhbnRlDQo-IA0KPiBKdWxpZSAoZW4gY2MpIHZhIHZvdXMgY29udGFjdGVyIHBvdXIgdHJvdXZlciB1biBjcsOpbmVhdSBkZSAzMG1pbiBwb3VyIHVuIGNhbGwuDQo-IA0KPiBQYXNzZXogdW5lIGV4Y2VsbGVudGUgZmluIGRlIHdlZWstZW5kLA0KPiANCj4gQSBiaWVudMO0dCwNCj4gDQo-IERhdmlkDQo-IA0KPiBEYXZpZCBBbGV4YW5kcmUgS2xpbmdiZWlsDQo-IENFTyAmIENvLUZvdW5kZXIgfCBEeW1hbnQuY29tDQo-IC4uLi4uLi4uLi4uLi4uLi4uLi4uLi4uLi4uLi4uLi4uLi4uLi4uLi4uLi4uLi4uLi4uLi4uLi4NCj4gTS4gZGFrQGR5bWFudC5jb20NCj4gVCAuICszMyA2IDYzIDk0IDc3IDQzDQo-IEBEYXZpZEtsaW5nYmVpbA0KPiAuLi4uLi4uLi4uLi4uLi4uLi4uLi4uLi4uLi4uLi4uLi4uLi4uLi4uLi4uLi4uLi4uLi4uLi4uDQo-IA0KPiANCj4gTGUgNSBqYW52aWVyIDIwMTUgMTM6MTksIEFybGVuZSBCZW50b2xpbGEgPGFybGVuZWJlbnRvbGlsYUBnbWFpbC5jb20-IGEgw6ljcml0IDoNCj4-IENoZXIgTW9uc2lldXIsDQo-PiANCj4-IEonYWkgbGUgcGxhaXNpciBkZSB2b3VzIGNvbnRhY3RlciBzdXIgbGVzIGNvbnNlaWxzIGRlIE1hZGFtZSBsZSBHb3VndWVjLCBEaXJlY3RyaWNlIHDDqWRhZ29naXF1ZSDDoCBTdXAgZGUgTHV4ZSBkYW5zIGxlIGNhZHJlIGRlIGxhIHByw6lwYXJhdGlvbiBkZSBtb24gbcOpbW9pcmUuIENlbHVpIC0gY2kgZG9pdCDDqnRyZSB1biByYXBwb3J0IHByb2Zlc3Npb25uZWwgY29uY3JldCBldCBwZXJ0aW5lbnQgZXQgbm9uIHBhcyAiYWNhZMOpbWlxdWUuIEplIHZvdXMgcHJvcG9zZSBkJ2VuIGTDqWNvdXZyaXIgbGUgc3VqZXQgZW4gcGnDqGNlIGpvaW50ZSBldCBsYSByw6lwb25zZSBkZSBTdXAgZGUgTHV4ZSBlbiBiYXMgZGUgY2UgbWFpbC4gDQo-PiANCj4-IERhbnMgbGEgcGVyc3BlY3RpdmUgZGUgdm91cyByZW5jb250cmVyLCBqZSBtZSBwcm9wb3NlIGRlIHZvdXMgcsOpc3VtZXIgbW9uIHBhcmNvdXJzIGV0IG1vbiBvYmplY3RpZiBwcm9mZXNzaW9ubmVscyBlbiByYXBwb3J0IGF2ZWMgbW9uIG3DqW1vaXJlLiANCj4-IA0KPj4gUGFyY291cnMNCj4-IEonYWkgdW5lIGV4cMOpcmllbmNlIHByb2Zlc3Npb25uZWxsZSBkZSBwcsOocyBkZSAxNSBhbnMgZW4gdGFudCBxdWUgRGlyZWN0cmljZSBkZSBjbGllbnTDqGxlIHByZXNzZSDDqWNyaXRlIGF1IHNlaW4gZGUgZ3JhbmRzIGdyb3VwZXMgbcOpZGlhcyAoVMOpbMOpcmFtYSwgTGFnYXJkw6hyZSkuIEonYWkgc3DDqWNpYWxpc8OpIGNldHRlIGV4cMOpcmllbmNlIGNvbW1lcmNpYWxlIGRlcHVpcyA4IGFucyBzdXIgbGVzIHNlY3RldXJzIGR1IGx1eGUgZXQgZGUgbGEgbW9kZSBlbiB0cmF2YWlsbGFudCBzdXIgbGVzIHByb2pldHMgZGUgY29tbXVuaWNhdGlvbiBwdWJsaWNpdGFpcmUgZGVzIGFubm9uY2V1cnMgZMOpZGnDqXMgZXQgcG91ciBkZXMgbWFycXVlcyBkZSBwcmVzc2UgaGF1dCBkZSBnYW1tZSBldCBsdXhlIChFbGxlLCBOdW3DqXJvLjs7KS4gTW9uIENWIGVzdCBlbiBwacOoY2Ugam9pbnRlLg0KPj4gDQo-PiBQcm9qZXQgcHJvZmVzc2lvbm5lbA0KPj4gSmUgdmV1eCBhbGxleiBwbHVzIGxvaW4gZGFucyBtb24gZMOpdmVsb3BwZW1lbnQgZGUgbWFycXVlcyBkZSBsdXhlIHNvaXQgYXUgbml2ZWF1IGNvbW1lcmNpYWwgc29pdCBhdSBuaXZlYXUgZGUgbGEgY29tbXVuaWNhdGlvbiBldCBjJ2VzdCBwb3VycXVvaSBqJ2FpIGludMOpZ3LDqSBTdXAgZGUgTHV4ZS4gSmUgdmlzZSBwb3VyIHNlcHRlbWJyZSBhdSBwbHVzIHRhcmQsIHVuZSBhY3Rpdml0w6kgY29tbWVyY2lhbGUgYXUgc2VpbiBkJ3VuZSBtYXJxdWUgZGUgbHV4ZS9tb2RlIG91IGVuIGFnZW5jZSAoZMOpdmVsb3BwZW1lbnQgb3UgY29uc2VpbCkuIFBvdXIgeSBwYXJ2ZW5pciBldCBlbnJpY2hpciBtYSB2YWxldXIgc3VyIGxlIG1hcmNow6ksIGplIGRvaXMgY29uc29saWRlciBjZSBxdWkgcydpbXBvc2UsIGxlIGRpZ2l0YWwhDQo-PiANCj4-IE3DqW1vaXJlIC0gcmFwcG9ydCBTdXAgZGUgTHV4ZQ0KPj4gSidhaSBkb25jIG9wdMOpIHBvdXIgdW4gc3VqZXQgZGUgbcOpbW9pcmUgcXVpIHBvcnRlIHN1ciBsZSBsdXhlIGTDqWZpw6kgcGFyIGxlIGRpZ2l0YWwuIEplIHZldXggZMOpbW9udHJlciBxdWUgbGUgbHV4ZSBlc3QgcsOpdGljZW50IGZhY2UgYXUgZGlnaXRhbCwgcG91cnRhbnQgZMOpY2lzaWYgZGFucyBsJ2FwcG9ydCBkZSBub3V2ZWF1eCBzZXJ2aWNlcyBldCBkYW5zIGxlIGTDqXBsb2llbWVudCBkdSBsdXhlLiAgDQo-PiBNYWlzIG1vbiBzdWpldCBlc3QgdHJvcCBsYXJnZS4gSmUgbmUgcGV1eCB0cmFpdGVyIGRlIHRvdXMgbGVzIHNlcnZpY2VzIGFwcG9ydMOpcyBwYXIgbGUgZGlnaXRhbC4gSidow6lzaXRlIGVudHJlIGxhIGNvbW11bmljYXRpb24gZXQgbGEgc3RyYXTDqWdpZSBkJ29mZnJlIChwcm9kdWl0cykuIFF1ZWwgZXN0IGxlIHBsdXMgInV0aWxlIGQnYXByw6hzIHZvdXMiPw0KPj4gRGUgcGx1cyBqZSBuZSBwZXV4IHRyYWl0ZXIgZHUgbHV4ZSBlbiBnw6luw6lyYWwuIEplIGRvaXMgY2hvaXNpciB1biBzZWdtZW50IGRlIGNlbHVpLWNpIC4gSmUgc291aGFpdGUgZm9jYWxpc2VyIHN1ciBsYSBqb2FpbGxlcmllIHF1aSBtZSBzZW1ibGUgcGx1cyBkw6lmacOpZSBwYXIgbGUgZGlnaXRhbCBjYXIgY2Ugc29udCBkZXV4ICJtYXJjaMOpcyIgYSBwcmlvcmkgYW50aW5vbWlxdWVzLiBDb21wcmVuZHJlIGxhIGNvbXBsZXhpdMOpIGR1IGR1byBKb2FpbGxlcmllIC8gZGlnaXRhbCBtZSBzZW1ibGUgw6lnYWxlbWVudCBwbHVzIGTDqXRlcm1pbmFudCBwb3VyIGNvbXByZW5kcmUgbGVzIGVuamV1eCBwb3PDqXMgcGFyIGxlIGRpZ2l0YWwuIFF1J2VuIHBlc25lei12b3VzPw0KPj4gDQo-PiBKZSB2b3VzIHJlbWVyY2llIHBhciBhdmFuY2UgcG91ciBsJ2F0dGVudGlvbiBxdWUgdm91cyBhY2NvcmRlcmV6IMOgIG1vbiBwcm9qZXQgZXQgamUgdm91cyBwcm9wb3NlIGRlIGNvbnZlbmlyIGQndW4gcmVuZGV6IC0gdm91cyBwb3VyIGF2YW5jZXIgc3VyIGNlbHVpLWNpLiBKZSBzdWlzIGRpc3BvbmlibGUgY2V0dGUgc2VtYWluZSDDoCB2b3RyZSBjb252ZW5hbmNlIGV0IHZvdXMgcG91dmV6IG3igJlhcHBlbGVyIGF1IDA2IDYyIDE4IDQ3IDA4Lg0KPj4gDQo-PiBCaWVuIMOgIHZvdXMsDQo-PiANCj4-IEFybMOobmUgQmVudG9saWxhDQo-PiANCj4-IA0KPj4gLS0tLS0tLS0tLSBNZXNzYWdlIHRyYW5zZsOpcsOpIC0tLS0tLS0tLS0NCj4-IERlIDogR2hpc2xhaW5lIExlIEdvdWd1ZWMgPGdsZWdvdWd1ZWNAZWRjcGFyaXMuZWR1Pg0KPj4gRGF0ZSA6IDE5IGTDqWNlbWJyZSAyMDE0IDE5OjQ2DQo-PiBPYmpldCA6IFJFOiBTdWpldCBkZSBtw6ltb2lyZSB1bmlxdWUgQXJsw6huZSBldCAiZXhlcmNpY2UiIDogamUgdmV1eCBkw6ltb250cmVyIHF1ZQ0KPj4gw4AgOiBBcmxlbmUgQmVudG9saWxhIDxhcmxlbmViZW50b2xpbGFAZ21haWwuY29tPg0KPj4gQ2MgOiB0ZGVsYXJpdmllcmUgPHRkZWxhcml2aWVyZUBlZGNwYXJpcy5lZHU-DQo-PiANCj4-IA0KPj4gQ2jDqHJlIEFybMOobmUsDQo-PiANCj4-IE1lcmNpIHBvdXIgY2VzIGluZm9ybWF0aW9ucy4NCj4-IA0KPj4gTm91cyBwcmVub25zIG5vdGUgZGUgdm90cmUgbm91dmVhdSBzdWpldCBkZSBtw6ltb2lyZSA6ICBMZXMgZMOpZmlzIGR1IGRpZ2l0YWwgZGFucyBsZXMgc3RyYXTDqWdpZXMgZGUgZMOpdmVsb3BwZW1lbnQgZHUgbHV4ZSBlbiBtYXRpw6hyZSAgZOKAmW9mZnJlLCBkZSBzZXJ2aWNlcywgZGUgZGlzdHJpYnV0aW9uIGV0IGRlIGNvbW11bmljYXRpb24NCj4-IA0KPj4gTm91cyBlbiB2YWxpZG9ucyBsZSB0aMOobWUgbWFpcyBwZW5zb25zIHRvdXRlZm9pcyBxdeKAmWlsIGVzdCBlbmNvcmUgdHJvcCBsYXJnZSBlbiB0ZXJtZSBkZSBww6lyaW3DqHRyZSBk4oCZYW5hbHlzZSArIGplIHBlbnNlIHF1ZSB2b3VzIGRldmV6IHZvdXMgY29uY2VudHJlciBzdXIgdW4gc2VjdGV1ciBldCBub24gbGUgbHV4ZSBlbiBnw6luw6lyYWwuDQo-PiANCj4-IFZvdXMgZGV2ZXogcmVuY29udHJlciBkZXMgcHJvZmVzc2lvbm5lbHMgcmFwaWRlbWVudCBxdWkgdm91cyBhaWRlcm9udCDDoCBkw6lmaW5pciB1bmUgcHJvYmzDqW1hdGlxdWUgcGx1cyBwcsOpY2lzZS4gTWVyY2kgZGUgY29udGFjdGVyIE3DqWxhbmllIHF1aSB2b3VzIGRvbm5lcmEgbGVzIGNvb3Jkb25uw6llcyBkZSBNb25zaWV1ciBHw6lyYWxkIEVTUEFSREVMTElFUiwgRGlyZWN0ZXVyIEFzc29jacOpIGRlIGxhIHNvY2nDqXTDqSBFTk9SQSBDb25zdWx0aW5nICsgY29udGFjdGV6IGRlIG5vdHJlIHBhcnQgRGF2aWQgQWxleGFuZHJlIEtsaW5nYmVpbCwgQ0VPICYgQ28tRm91bmRlciB8IER5bWFudC5jb20gLSAgZGFrQGR5bWFudC5jb20gKyBjbyBmb25kYXRldXIgZHUgbWFnYXppbmUgZGlnaXRhbCBXZWIgJiBMdXhlIGh0dHA6Ly93d3cud2ViYW5kbHV4ZS5jb20vYS1wcm9wb3MvDQo-PiANCj4-IEJpZW4gw6Agdm91cywNCj4-IA0KPj4gR2xHDQo-PiANCj4-ICANCj4-IA0KPj4gIA0KPj4gDQo-PiBEZSA6IEFybGVuZSBCZW50b2xpbGEgW21haWx0bzphcmxlbmViZW50b2xpbGFAZ21haWwuY29tXSANCj4-IEVudm95w6kgOiB2ZW5kcmVkaSAxOSBkw6ljZW1icmUgMjAxNCAxOToxOA0KPj4gw4AgOiBnaGlzbGFpbmUubGVnb3VndWVjQGVkY3BhcmlzLmVkdQ0KPj4gQ2MgOiB0aGliYXV0LmRlbGFyaXZpZXJlQGVkY3BhcmlzLmVkdQ0KPj4gT2JqZXQgOiBTdWpldCBkZSBtw6ltb2lyZSB1bmlxdWUgQXJsw6huZSBldCAiZXhlcmNpY2UiIDogamUgdmV1eCBkw6ltb250cmVyIHF1ZQ0KPj4gDQo-PiAgDQo-PiANCj4-IENoZXJzIHRvdXMNCj4-IA0KPj4gIA0KPj4gDQo-PiBKJ2FpIHJlcGVuc8OpIG1vbiBzdWpldCBkZSBtw6ltb2lyZSBlbiBmb25jdGlvbiBkZSBtZXMgZ2_Du3RzLCBkZSBtZXMgY29tcMOpdGVuY2VzIGV0IGRlIG1lcyBvYmplY3RpZnMgcHJvZmVzc2lvbm5lbHMuIA0KPj4gDQo-PiAgDQo-PiANCj4-IEplIHBhcnMgZG9uYyBzdXIgbGEgdmVyc2lvbiBxdWUgdm91cyBkw6ljb3V2cmlyZXogZW4gcGnDqGNlIGpvaW50ZSBldCBxdWkgcG9ydGUgc3VyIGxlcyBlbmpldXggZHUgZGlnaXRhbCBkYW5zIGxlcyBzdHJhdMOpZ2llcyBkZSBkw6l2ZWxvcHBlbWVudCBkdSBsdXhlIGVuIG1hdGnDqHJlIGQnb2ZmcmUsIGRlIHNlcnZpY2UsIGRlIGRpc3RyaWJ1dGlvbiBldCBkZSBjb21tdW5pY2F0aW9uLiANCj4-IA0KPj4gSmUgbWUgc3VpcyDDqWdhbGVtZW50IHByw6p0w6llIGF1IG7DqWNlc3NhaXJlIGV4ZXJjaWNlIGR1IDogICJqZSB2ZXV4IGTDqW1vbnRyZXIgcXVlIi4NCj4-IA0KPj4gIA0KPj4gDQo-PiBKZSByZXN0ZSDDoCB2b3RyZSDDqWNvdXRlIHBvdXIgZmluYWxpc2VyIGNldHRlIGZpY2hlIHDDqWRhZ29naXF1ZSBldCB2YWxpZGVyIG1vbiBzdWpldCBkZSBtw6ltb2lyZSBhdmFudCBsYSByZW50csOpZSBkZSBqYW52aWVyIHNpIGNlbGEgdm91cyBlc3QgcG9zc2libGUuIEplIHZhaXMgZCdvcmVzIGV0IGTDqWrDoCBjb21tZW5jZXIgbWVzIHJlY2hlcmNoZXMgZXQgZmFpcmUgdW5lIMOpYmF1Y2hlIGRlIHBsYW4gcGVuZGFudCBjZXMgdmFjYW5jZXMuIA0KPj4gDQo-PiAgDQo-PiANCj4-IEplIHZvdXMgc291aGFpdGUgZGUgdHLDqHMgYm9ubmVzIGbDqnRlcy4NCj4-IA0KPj4gIA0KPj4gDQo-PiBCaWVuIMOgIHZvdXMsDQo-PiANCj4-ICANCj4-IA0KPj4gQXJsw6huZQ0KPj4gDQo-IA0K"}}, {:partId=>"1", :mimeType=>"text/html", :filename=>"", :headers=>[{:name=>"Content-Type", :value=>"text/html; charset=utf-8"}, {:name=>"Content-Transfer-Encoding", :value=>"quoted-printable"}], :body=>{:size=>13612, :data=>"PGh0bWw-PGhlYWQ-PG1ldGEgaHR0cC1lcXVpdj0iY29udGVudC10eXBlIiBjb250ZW50PSJ0ZXh0L2h0bWw7IGNoYXJzZXQ9dXRmLTgiPjwvaGVhZD48Ym9keSBkaXI9ImF1dG8iPjxkaXY-PGRpdj48cCBjbGFzcz0iTXNvTm9ybWFsIiBzdHlsZT0ibWFyZ2luOiAwY20gMGNtIDAuMDAwMXB0OyI-PHNwYW4gc3R5bGU9ImJhY2tncm91bmQtY29sb3I6IHJnYmEoMjU1LCAyNTUsIDI1NSwgMCk7Ij48Yj5Cb25zb2lyIERhdmlkPC9iPjwvc3Bhbj48L3A-PHAgY2xhc3M9Ik1zb05vcm1hbCIgc3R5bGU9Im1hcmdpbjogMGNtIDBjbSAwLjAwMDFwdDsiPjxzcGFuIHN0eWxlPSJiYWNrZ3JvdW5kLWNvbG9yOiByZ2JhKDI1NSwgMjU1LCAyNTUsIDApOyI-PGI-PGJyPjwvYj48L3NwYW4-PC9wPjxwIGNsYXNzPSJNc29Ob3JtYWwiIHN0eWxlPSJtYXJnaW46IDBjbSAwY20gMC4wMDAxcHQ7Ij48Yj5NZXJjaSBwb3VyIHZvdHJlIHJldG91ci4gSmUgdmVycmFpIGRlbWFpbiBhdmVjIEp1bGllLCBxdWFuZCBmaXhlciB1biBSRFYgdMOpbMOpcGhvbmlxdWUuJm5ic3A7PC9iPjwvcD48cCBjbGFzcz0iTXNvTm9ybWFsIiBzdHlsZT0ibWFyZ2luOiAwY20gMGNtIDAuMDAwMXB0OyI-PGI-PGJyPjwvYj48L3A-PHAgY2xhc3M9Ik1zb05vcm1hbCIgc3R5bGU9Im1hcmdpbjogMGNtIDBjbSAwLjAwMDFwdDsiPjxiPlBvdXIgaW5mb3JtYXRpb24sIGonYWkgYWp1c3TDqSBtb24gc3VqZXQgZGUgbcOpbW9pcmUgcXVlIGplIHRyb3V2YWlzIHRyb3AgY2xhc3NpcXVlIGV0IGNlLCBhcHLDqHMgYXZvaXIgw6ljaGFuZ8OpIGF2ZWMgZGVzIGNvbnN1bHRhbnRzLiAmbmJzcDs8L2I-PC9wPjxwIGNsYXNzPSJNc29Ob3JtYWwiIHN0eWxlPSJtYXJnaW46IDBjbSAwY20gMC4wMDAxcHQ7Ij48Yj5KZSB2b3VzIGwnZXhwb3NlIGNpLWRlc3NvdXMuIFZvcyBjb25zZWlscyBldCByZW1hcnF1ZXMgbWUgc2Vyb250IHRyZXMgdXRpbGVzLiAmbmJzcDs8L2I-PC9wPjxwIGNsYXNzPSJNc29Ob3JtYWwiIHN0eWxlPSJtYXJnaW46IDBjbSAwY20gMC4wMDAxcHQ7Ij48Yj48YnI-PC9iPjwvcD48cCBjbGFzcz0iTXNvTm9ybWFsIiBzdHlsZT0ibWFyZ2luOiAwY20gMGNtIDAuMDAwMXB0OyI-PGI-U3VqZXQgKGVudm95w6kgw6AgU3VwIGRlIEx1eGUgYXZhbnQgaGllciwgVmVuZHJlZGkpOiZuYnNwOzwvYj48L3A-PHAgY2xhc3M9Ik1zb05vcm1hbCIgc3R5bGU9Im1hcmdpbjogMGNtIDBjbSAwLjAwMDFwdDsiPjxzcGFuIHN0eWxlPSJiYWNrZ3JvdW5kLWNvbG9yOiByZ2JhKDI1NSwgMjU1LCAyNTUsIDApOyI-PGI-PGJyPjwvYj48L3NwYW4-PC9wPjxwIGNsYXNzPSJNc29Ob3JtYWwiIHN0eWxlPSJtYXJnaW46IDBjbSAwY20gMC4wMDAxcHQ7Ij48c3BhbiBzdHlsZT0iYmFja2dyb3VuZC1jb2xvcjogcmdiYSgyNTUsIDI1NSwgMjU1LCAwKTsiPjxiPkNvbW1lbnQgbGVzIG1hcnF1ZXMgZGUgbW9kZSBldCBkZSBqb2FpbGxlcmllIHMneSBwcmVubmVudCBwb3VyIGFwcHLDqWhlbmRlciBsZXMgb2JqZXRzIGNvbm5lY3TDqXMgZGFucyBsZXVyIHN0cmF0w6lnaWUgZCdvZmZyZT8mbmJzcDs8L2I-PG86cD48L286cD48L3NwYW4-PC9wPjwvZGl2PjxkaXY-PHAgY2xhc3M9Ik1zb05vcm1hbCIgc3R5bGU9Im1hcmdpbjogMGNtIDBjbSAwLjAwMDFwdDsiPjxzcGFuIHN0eWxlPSJiYWNrZ3JvdW5kLWNvbG9yOiByZ2JhKDI1NSwgMjU1LCAyNTUsIDApOyI-SmUgdmV1eCBkw6ltb250cmVyIHF1ZSBsZXMgb2JqZXRzIGNvbm5lY3TDqXMgc29udCB1biBsZXZpZXIgZGUgY3JvaXNzYW5jZSBldCBkZSBkaWZmw6lyZW5jaWF0aW9uLiBKZSB2ZXV4IGFuYWx5c2VyIGxlcyBjb21wb3J0ZW1lbnRzIGRlcyBtYXJxdWVzIGZhY2Ugw6AgY2V0IGVuamV1eDogdm9udCAtIGVsbGVzIHJlc3TDqWVzIGRhbnMgbGUgY2xhc3NpY2lzbWUgYXZlYyBkZXMgbWF0acOocmVzIG5vYmxlcyBwYXIgZXhlbXBsZSBvdSDDqXZvbHVlciBkZSBmYcOnb24gc2lnbmlmaWNhdGl2ZXMgYXZlYyBsZXMgb2JqZXRzIGNvbm5lY3TDqXM_IENvbW1lbnQgYXBwcsOpaGVuZGVudCAtIGVsbGVzIGNlIGNoYW5nZW1lbnQgZGlnaXRhbCBkYW5zIGxldXIgc3RyYXTDqWdpZSBk4oCZb2ZmcmUgZXQgZGUgZMOpdmVsb3BwZW1lbnQ_PC9zcGFuPjwvcD48cCBjbGFzcz0iTXNvTm9ybWFsIiBzdHlsZT0ibWFyZ2luOiAwY20gMGNtIDAuMDAwMXB0OyI-PHNwYW4gc3R5bGU9ImJhY2tncm91bmQtY29sb3I6IHJnYmEoMjU1LCAyNTUsIDI1NSwgMCk7Ij48YnI-PC9zcGFuPjwvcD48cCBjbGFzcz0iTXNvTm9ybWFsIiBzdHlsZT0ibWFyZ2luOiAwY20gMGNtIDAuMDAwMXB0OyI-PHNwYW4gc3R5bGU9ImJhY2tncm91bmQtY29sb3I6IHJnYmEoMjU1LCAyNTUsIDI1NSwgMCk7Ij5CaWVuIMOgIHZvdXMmbmJzcDs8L3NwYW4-PC9wPjxwIGNsYXNzPSJNc29Ob3JtYWwiIHN0eWxlPSJtYXJnaW46IDBjbSAwY20gMC4wMDAxcHQ7Ij5BcmzDqG5lPC9wPjwvZGl2Pjxicj5BcmzDqG5lIEJlbnRvbGlsYTxkaXY-RW52b3nDqSBkZSBtb24gaVBob25lLjwvZGl2PjxkaXY-MDYgNjIgMTggNDcgMDg8L2Rpdj48ZGl2Pjxicj48L2Rpdj48L2Rpdj48ZGl2Pjxicj5MZSAxMSBqYW52LiAyMDE1IMOgIDE5OjUzLCBEYXZpZCBBbGV4YW5kcmUgS2xpbmdiZWlsICZsdDs8YSBocmVmPSJtYWlsdG86ZGFrQGR5bWFudC5jb20iPmRha0BkeW1hbnQuY29tPC9hPiZndDsgYSDDqWNyaXQmbmJzcDs6PGJyPjxicj48L2Rpdj48YmxvY2txdW90ZSB0eXBlPSJjaXRlIj48ZGl2PjxkaXYgZGlyPSJsdHIiPkJvbnNvaXIgQXJsZW5lLDxkaXY-PGJyPjwvZGl2PjxkaXY-UGFybG9ucy1lbiBwYXIgdMOpbMOpcGhvbmUgY2V0dGUgc2VtYWluZSBvdSBsYSBzdWl2YW50ZTwvZGl2PjxkaXY-PGJyPjwvZGl2PjxkaXY-SnVsaWUgKGVuIGNjKSB2YSB2b3VzIGNvbnRhY3RlciBwb3VyIHRyb3V2ZXIgdW4gY3LDqW5lYXUgZGUgMzBtaW4gcG91ciB1biBjYWxsLjwvZGl2PjxkaXY-PGJyPjwvZGl2PjxkaXY-UGFzc2V6IHVuZSBleGNlbGxlbnRlIGZpbiBkZSB3ZWVrLWVuZCw8L2Rpdj48ZGl2Pjxicj48L2Rpdj48ZGl2PkEgYmllbnTDtHQsPC9kaXY-PGRpdj48YnI-PC9kaXY-PGRpdj5EYXZpZDwvZGl2PjwvZGl2PjxiciBjbGVhcj0iYWxsIj48ZGl2PjxkaXYgY2xhc3M9ImdtYWlsX3NpZ25hdHVyZSI-PGRpdiBkaXI9Imx0ciI-PGRpdj48Yj5EYXZpZCBBbGV4YW5kcmUgS2xpbmdiZWlsPC9iPjwvZGl2PjxkaXY-PHNwYW4gc3R5bGU9ImNvbG9yOnJnYig1MSw1MSw1MSkiPkNFTyAmYW1wOyZuYnNwOzwvc3Bhbj48Zm9udCBjb2xvcj0iIzMzMzMzMyI-Q28tRm91bmRlciB8IDxhIGhyZWY9Imh0dHA6Ly9EeW1hbnQuY29tIiB0YXJnZXQ9Il9ibGFuayI-PGZvbnQgY29sb3I9IiMzMzMzMzMiPjxiPkR5bWFudC5jb208L2I-PC9mb250PjwvYT48L2ZvbnQ-PC9kaXY-PGRpdj4uLi4uLi4uLi4uLi4uLi4uLi4uLi4uLi4uLi4uLi4uLi4uLi4uLi4uLi4uLi4uLi4uLi4uLi4uPC9kaXY-PGRpdj5NLiA8YSBocmVmPSJtYWlsdG86ZGFrQGR5bWFudC5jb20iIHRhcmdldD0iX2JsYW5rIj5kYWtAZHltYW50LmNvbTwvYT48L2Rpdj48ZGl2PlQgLiArMzMgNiA2MyA5NCA3NyA0MzwvZGl2PjxkaXY-PGEgaHJlZj0iaHR0cDovL3d3dy50d2l0dGVyLmNvbS9kYXZpZGtsaW5nYmVpbCIgdGFyZ2V0PSJfYmxhbmsiPkBEYXZpZEtsaW5nYmVpbDwvYT48L2Rpdj48ZGl2Pi4uLi4uLi4uLi4uLi4uLi4uLi4uLi4uLi4uLi4uLi4uLi4uLi4uLi4uLi4uLi4uLi4uLi4uLi48L2Rpdj48ZGl2PjxpbWcgc3JjPSJodHRwOi8vd3d3LmR5bWFudC5jb20vbWVkaWEvdG1wL2NhdGFsb2cvcHJvZHVjdC9kL3kvZHltYW50LWxvZ28tbWFpbC5wbmciPjxicj48L2Rpdj48L2Rpdj48L2Rpdj48L2Rpdj4NCjxkaXYgY2xhc3M9ImdtYWlsX2V4dHJhIj48YnI-PGRpdiBjbGFzcz0iZ21haWxfcXVvdGUiPkxlIDUgamFudmllciAyMDE1IDEzOjE5LCBBcmxlbmUgQmVudG9saWxhIDxzcGFuIGRpcj0ibHRyIj4mbHQ7PGEgaHJlZj0ibWFpbHRvOmFybGVuZWJlbnRvbGlsYUBnbWFpbC5jb20iIHRhcmdldD0iX2JsYW5rIj5hcmxlbmViZW50b2xpbGFAZ21haWwuY29tPC9hPiZndDs8L3NwYW4-IGEgw6ljcml0IDo8YnI-PGJsb2NrcXVvdGUgY2xhc3M9ImdtYWlsX3F1b3RlIiBzdHlsZT0ibWFyZ2luOjAgMCAwIC44ZXg7Ym9yZGVyLWxlZnQ6MXB4ICNjY2Mgc29saWQ7cGFkZGluZy1sZWZ0OjFleCI-PGRpdiBkaXI9Imx0ciI-PHNwYW4gc3R5bGU9ImZvbnQtc2l6ZToxM3B4Ij5DaGVyIE1vbnNpZXVyLDwvc3Bhbj48ZGl2Pjxicj48L2Rpdj48ZGl2PkonYWkgbGUgcGxhaXNpciBkZSB2b3VzIGNvbnRhY3RlciBzdXIgbGVzIGNvbnNlaWxzIGRlIE1hZGFtZSBsZSBHb3VndWVjLCBEaXJlY3RyaWNlIHDDqWRhZ29naXF1ZSDDoCBTdXAgZGUgTHV4ZSBkYW5zIGxlIGNhZHJlIGRlIGxhIHByw6lwYXJhdGlvbiBkZSBtb24gbcOpbW9pcmUuIENlbHVpIC0gY2kgZG9pdCDDqnRyZSB1biByYXBwb3J0IHByb2Zlc3Npb25uZWwgY29uY3JldCBldCBwZXJ0aW5lbnQgZXQgbm9uIHBhcyAiYWNhZMOpbWlxdWUuIEplIHZvdXMgcHJvcG9zZSBkJ2VuIGTDqWNvdXZyaXIgbGUgc3VqZXQgZW4gcGnDqGNlIGpvaW50ZSBldCBsYSByw6lwb25zZSBkZSBTdXAgZGUgTHV4ZSBlbiBiYXMgZGUgY2UgbWFpbC4mbmJzcDs8L2Rpdj48ZGl2Pjxicj48L2Rpdj48ZGl2PkRhbnMgbGEgcGVyc3BlY3RpdmUgZGUgdm91cyByZW5jb250cmVyLCBqZSBtZSBwcm9wb3NlIGRlIHZvdXMgcsOpc3VtZXIgbW9uIHBhcmNvdXJzIGV0IG1vbiBvYmplY3RpZiBwcm9mZXNzaW9ubmVscyBlbiByYXBwb3J0IGF2ZWMgbW9uIG3DqW1vaXJlLiZuYnNwOzwvZGl2PjxkaXY-PGJyPjwvZGl2PjxkaXY-PHNwYW4gc3R5bGU9ImZvbnQtc2l6ZToxM3B4Ij48Yj5QYXJjb3VyczwvYj48L3NwYW4-PC9kaXY-PGRpdj5KJ2FpIHVuZSBleHDDqXJpZW5jZSBwcm9mZXNzaW9ubmVsbGUgZGUgcHLDqHMgZGUgMTUgYW5zIGVuIHRhbnQgcXVlIERpcmVjdHJpY2UgZGUgY2xpZW50w6hsZSBwcmVzc2Ugw6ljcml0ZSBhdSBzZWluIGRlIGdyYW5kcyBncm91cGVzJm5ic3A7bcOpZGlhcyZuYnNwOyhUw6lsw6lyYW1hLCBMYWdhcmTDqHJlKS4gSidhaSBzcMOpY2lhbGlzw6kgY2V0dGUmbmJzcDtleHDDqXJpZW5jZSBjb21tZXJjaWFsZSBkZXB1aXMgOCBhbnMgc3VyIGxlcyBzZWN0ZXVycyBkdSBsdXhlIGV0IGRlIGxhIG1vZGUgZW4gdHJhdmFpbGxhbnQgc3VyIGxlcyBwcm9qZXRzIGRlIGNvbW11bmljYXRpb24gcHVibGljaXRhaXJlIGRlcyBhbm5vbmNldXJzIGTDqWRpw6lzIGV0IHBvdXIgZGVzIG1hcnF1ZXMgZGUgcHJlc3NlIGhhdXQgZGUgZ2FtbWUgZXQgbHV4ZSAoRWxsZSwgTnVtw6lyby47OykuIE1vbiBDViBlc3QgZW4gcGnDqGNlIGpvaW50ZS48YnI-PC9kaXY-PGRpdj48ZGl2IHN0eWxlPSJmb250LXNpemU6MTNweCI-PGJyPjwvZGl2PjxkaXYgc3R5bGU9ImZvbnQtc2l6ZToxM3B4Ij48Yj5Qcm9qZXQgcHJvZmVzc2lvbm5lbDwvYj48L2Rpdj48ZGl2IHN0eWxlPSJmb250LXNpemU6MTNweCI-SmUgdmV1eCBhbGxleiBwbHVzIGxvaW4gZGFucyBtb24gZMOpdmVsb3BwZW1lbnQgZGUgbWFycXVlcyBkZSBsdXhlIHNvaXQgYXUgbml2ZWF1IGNvbW1lcmNpYWwgc29pdCBhdSBuaXZlYXUgZGUgbGEgY29tbXVuaWNhdGlvbiBldCBjJ2VzdCBwb3VycXVvaSBqJ2FpIGludMOpZ3LDqSBTdXAgZGUgTHV4ZS4gSmUgdmlzZSBwb3VyIHNlcHRlbWJyZSBhdSBwbHVzIHRhcmQsIHVuZSBhY3Rpdml0w6kgY29tbWVyY2lhbGUgYXUgc2VpbiBkJ3VuZSBtYXJxdWUgZGUgbHV4ZS9tb2RlIG91IGVuIGFnZW5jZSAoZMOpdmVsb3BwZW1lbnQgb3UgY29uc2VpbCkuIFBvdXIgeSBwYXJ2ZW5pciBldCBlbnJpY2hpciBtYSB2YWxldXIgc3VyIGxlIG1hcmNow6ksIGplIGRvaXMgY29uc29saWRlciBjZSBxdWkgcydpbXBvc2UsIGxlIGRpZ2l0YWwhPC9kaXY-PGRpdiBzdHlsZT0iZm9udC1zaXplOjEzcHgiPjxicj48L2Rpdj48ZGl2IHN0eWxlPSJmb250LXNpemU6MTNweCI-PGI-TcOpbW9pcmUgLSByYXBwb3J0IFN1cCBkZSBMdXhlPC9iPjwvZGl2PjxkaXYgc3R5bGU9ImZvbnQtc2l6ZToxM3B4Ij5KJ2FpIGRvbmMgb3B0w6kgcG91ciB1biBzdWpldCBkZSBtw6ltb2lyZSBxdWkgcG9ydGUgc3VyIGxlIGx1eGUgZMOpZmnDqSBwYXIgbGUgZGlnaXRhbC4gSmUgdmV1eCBkw6ltb250cmVyIHF1ZSBsZSBsdXhlIGVzdCByw6l0aWNlbnQgZmFjZSBhdSBkaWdpdGFsLCBwb3VydGFudCBkw6ljaXNpZiBkYW5zIGwnYXBwb3J0IGRlIG5vdXZlYXV4IHNlcnZpY2VzIGV0IGRhbnMgbGUgZMOpcGxvaWVtZW50IGR1IGx1eGUuICZuYnNwOzwvZGl2PjxkaXYgc3R5bGU9ImZvbnQtc2l6ZToxM3B4Ij48dWw-PGxpIHN0eWxlPSJtYXJnaW4tbGVmdDoxNXB4Ij5NYWlzIG1vbiBzdWpldCBlc3QgdHJvcCBsYXJnZS4gSmUgbmUgcGV1eCB0cmFpdGVyIGRlIHRvdXMgbGVzIHNlcnZpY2VzIGFwcG9ydMOpcyBwYXIgbGUgZGlnaXRhbC4gSidow6lzaXRlIGVudHJlIGxhIGNvbW11bmljYXRpb24gZXQgbGEgc3RyYXTDqWdpZSBkJ29mZnJlIChwcm9kdWl0cykuIFF1ZWwgZXN0IGxlIHBsdXMgInV0aWxlIGQnYXByw6hzIHZvdXMiPzwvbGk-PC91bD48dWw-PGxpIHN0eWxlPSJtYXJnaW4tbGVmdDoxNXB4Ij5EZSBwbHVzIGplIG5lIHBldXggdHJhaXRlciBkdSBsdXhlIGVuIGfDqW7DqXJhbC4gSmUgZG9pcyBjaG9pc2lyIHVuIHNlZ21lbnQgZGUgY2VsdWktY2kgLiBKZSBzb3VoYWl0ZSBmb2NhbGlzZXIgc3VyIGxhIGpvYWlsbGVyaWUgcXVpIG1lIHNlbWJsZSBwbHVzIGTDqWZpw6llIHBhciBsZSBkaWdpdGFsIGNhciBjZSBzb250IGRldXggIm1hcmNow6lzIiBhIHByaW9yaSBhbnRpbm9taXF1ZXMuIENvbXByZW5kcmUgbGEgY29tcGxleGl0w6kgZHUgZHVvIEpvYWlsbGVyaWUgLyBkaWdpdGFsIG1lIHNlbWJsZSDDqWdhbGVtZW50IHBsdXMgZMOpdGVybWluYW50IHBvdXIgY29tcHJlbmRyZSBsZXMgZW5qZXV4IHBvc8OpcyBwYXIgbGUgZGlnaXRhbC4gUXUnZW4gcGVzbmV6LXZvdXM_PC9saT48L3VsPjwvZGl2PjxkaXYgc3R5bGU9ImZvbnQtc2l6ZToxM3B4Ij48YnI-PC9kaXY-PGRpdiBzdHlsZT0iZm9udC1zaXplOjEzcHgiPkplIHZvdXMgcmVtZXJjaWUgcGFyIGF2YW5jZSBwb3VyIGwnYXR0ZW50aW9uIHF1ZSB2b3VzIGFjY29yZGVyZXogw6AgbW9uIHByb2pldCBldCBqZSB2b3VzIHByb3Bvc2UgZGUgY29udmVuaXIgZCd1biByZW5kZXogLSB2b3VzIHBvdXIgYXZhbmNlciBzdXIgY2VsdWktY2kuIEplIHN1aXMgZGlzcG9uaWJsZSBjZXR0ZSBzZW1haW5lIMOgIHZvdHJlIGNvbnZlbmFuY2UgZXQgdm91cyBwb3V2ZXogbeKAmWFwcGVsZXIgYXUgPGEgaHJlZj0idGVsOjA2JTIwNjIlMjAxOCUyMDQ3JTIwMDgiIHZhbHVlPSIrMzM2NjIxODQ3MDgiIHRhcmdldD0iX2JsYW5rIj4wNiA2MiAxOCA0NyAwODwvYT4uPC9kaXY-PGRpdiBzdHlsZT0iZm9udC1zaXplOjEzcHgiPjxicj48L2Rpdj48ZGl2IHN0eWxlPSJmb250LXNpemU6MTNweCI-QmllbiDDoCB2b3VzLDwvZGl2PjxkaXYgc3R5bGU9ImZvbnQtc2l6ZToxM3B4Ij48YnI-PC9kaXY-PGRpdiBzdHlsZT0iZm9udC1zaXplOjEzcHgiPkFybMOobmUgQmVudG9saWxhPC9kaXY-PGRpdiBzdHlsZT0iZm9udC1zaXplOjEzcHgiPjxicj48L2Rpdj48ZGl2IHN0eWxlPSJmb250LXNpemU6MTNweCI-PGJyPjwvZGl2PjwvZGl2PjxkaXYgY2xhc3M9ImdtYWlsX3F1b3RlIj4tLS0tLS0tLS0tIE1lc3NhZ2UgdHJhbnNmw6lyw6kgLS0tLS0tLS0tLTxicj5EZSZuYnNwOzogPGIgY2xhc3M9ImdtYWlsX3NlbmRlcm5hbWUiPkdoaXNsYWluZSBMZSBHb3VndWVjPC9iPiA8c3BhbiBkaXI9Imx0ciI-Jmx0OzxhIGhyZWY9Im1haWx0bzpnbGVnb3VndWVjQGVkY3BhcmlzLmVkdSIgdGFyZ2V0PSJfYmxhbmsiPmdsZWdvdWd1ZWNAZWRjcGFyaXMuZWR1PC9hPiZndDs8L3NwYW4-PGJyPkRhdGUmbmJzcDs6IDE5IGTDqWNlbWJyZSAyMDE0IDE5OjQ2PGJyPk9iamV0Jm5ic3A7OiBSRTogU3VqZXQgZGUgbcOpbW9pcmUgdW5pcXVlIEFybMOobmUgZXQgImV4ZXJjaWNlIiA6IGplIHZldXggZMOpbW9udHJlciBxdWU8YnI-w4AmbmJzcDs6IEFybGVuZSBCZW50b2xpbGEgJmx0OzxhIGhyZWY9Im1haWx0bzphcmxlbmViZW50b2xpbGFAZ21haWwuY29tIiB0YXJnZXQ9Il9ibGFuayI-YXJsZW5lYmVudG9saWxhQGdtYWlsLmNvbTwvYT4mZ3Q7PGJyPkNjIDogdGRlbGFyaXZpZXJlICZsdDs8YSBocmVmPSJtYWlsdG86dGRlbGFyaXZpZXJlQGVkY3BhcmlzLmVkdSIgdGFyZ2V0PSJfYmxhbmsiPnRkZWxhcml2aWVyZUBlZGNwYXJpcy5lZHU8L2E-Jmd0Ozxicj48YnI-PGJyPjxkaXYgbGFuZz0iRlIiIGxpbms9ImJsdWUiIHZsaW5rPSJwdXJwbGUiPjxkaXY-PHAgY2xhc3M9Ik1zb05vcm1hbCI-PHNwYW4gc3R5bGU9ImZvbnQtc2l6ZToxMXB0O2ZvbnQtZmFtaWx5OidNYWlhbmRyYSBHRCcsc2Fucy1zZXJpZjtjb2xvcjpibGFjayI-Q2jDqHJlIEFybMOobmUsPHU-PC91Pjx1PjwvdT48L3NwYW4-PC9wPjxwIGNsYXNzPSJNc29Ob3JtYWwiPjxzcGFuIHN0eWxlPSJmb250LXNpemU6MTFwdDtmb250LWZhbWlseTonTWFpYW5kcmEgR0QnLHNhbnMtc2VyaWY7Y29sb3I6YmxhY2siPk1lcmNpIHBvdXIgY2VzIGluZm9ybWF0aW9ucy4gPHU-PC91Pjx1PjwvdT48L3NwYW4-PC9wPjxwIGNsYXNzPSJNc29Ob3JtYWwiPjxzcGFuIHN0eWxlPSJmb250LXNpemU6MTFwdDtmb250LWZhbWlseTonTWFpYW5kcmEgR0QnLHNhbnMtc2VyaWY7Y29sb3I6YmxhY2siPk5vdXMgcHJlbm9ucyBub3RlIGRlIHZvdHJlIG5vdXZlYXUgc3VqZXQgZGUgbcOpbW9pcmUmbmJzcDs6ICZuYnNwOzwvc3Bhbj48Yj48dT48c3BhbiBzdHlsZT0iZm9udC1zaXplOjExcHQ7Zm9udC1mYW1pbHk6J01haWFuZHJhIEdEJyxzYW5zLXNlcmlmO2NvbG9yOmJsYWNrIj5MZXMgZMOpZmlzPGEgbmFtZT0iMTRhYmEwOTg2OTQwNTdiNl8xNGE2M2RlZjk5ZmU2NzJhX19Hb0JhY2siPjwvYT4gZHUgZGlnaXRhbCBkYW5zIGxlcyBzdHJhdMOpZ2llcyBkZSBkw6l2ZWxvcHBlbWVudCBkdSBsdXhlIGVuIG1hdGnDqHJlJm5ic3A7IGTigJlvZmZyZSwgZGUgc2VydmljZXMsIGRlIGRpc3RyaWJ1dGlvbiBldCBkZSBjb21tdW5pY2F0aW9uPC9zcGFuPjwvdT48L2I-PHU-PHNwYW4gc3R5bGU9ImZvbnQtc2l6ZToxMXB0O2ZvbnQtZmFtaWx5OidNYWlhbmRyYSBHRCcsc2Fucy1zZXJpZjtjb2xvcjpibGFjayI-PHU-PC91Pjx1PjwvdT48L3NwYW4-PC91PjwvcD48cCBjbGFzcz0iTXNvTm9ybWFsIj48c3BhbiBzdHlsZT0iZm9udC1zaXplOjExcHQ7Zm9udC1mYW1pbHk6J01haWFuZHJhIEdEJyxzYW5zLXNlcmlmO2NvbG9yOmJsYWNrIj5Ob3VzIGVuIHZhbGlkb25zIGxlIHRow6htZSBtYWlzIHBlbnNvbnMgdG91dGVmb2lzIHF14oCZaWwgZXN0IGVuY29yZSB0cm9wIGxhcmdlIGVuIHRlcm1lIGRlIHDDqXJpbcOodHJlIGTigJlhbmFseXNlICsgamUgcGVuc2UgcXVlIHZvdXMgZGV2ZXogdm91cyBjb25jZW50cmVyIHN1ciB1biBzZWN0ZXVyIGV0IG5vbiBsZSBsdXhlIGVuIGfDqW7DqXJhbC48dT48L3U-PHU-PC91Pjwvc3Bhbj48L3A-PHAgY2xhc3M9Ik1zb05vcm1hbCI-PHNwYW4gc3R5bGU9ImZvbnQtc2l6ZToxMXB0O2ZvbnQtZmFtaWx5OidNYWlhbmRyYSBHRCcsc2Fucy1zZXJpZjtjb2xvcjpibGFjayI-Vm91cyBkZXZleiByZW5jb250cmVyIGRlcyBwcm9mZXNzaW9ubmVscyByYXBpZGVtZW50IHF1aSB2b3VzIGFpZGVyb250IMOgIGTDqWZpbmlyIHVuZSBwcm9ibMOpbWF0aXF1ZSBwbHVzIHByw6ljaXNlLiBNZXJjaSBkZSBjb250YWN0ZXIgTcOpbGFuaWUgcXVpIHZvdXMgZG9ubmVyYSBsZXMgY29vcmRvbm7DqWVzIGRlIE1vbnNpZXVyIEfDqXJhbGQgRVNQQVJERUxMSUVSLCBEaXJlY3RldXIgQXNzb2Npw6kgZGUgbGEgc29jacOpdMOpIEVOT1JBIENvbnN1bHRpbmcgKyBjb250YWN0ZXogZGUgbm90cmUgcGFydCBEYXZpZCBBbGV4YW5kcmUgS2xpbmdiZWlsLCBDRU8gJmFtcDsmbmJzcDtDby1Gb3VuZGVyIHwgPGEgaHJlZj0iaHR0cDovL0R5bWFudC5jb20iIHRhcmdldD0iX2JsYW5rIj48c3BhbiBzdHlsZT0iY29sb3I6YmxhY2s7dGV4dC1kZWNvcmF0aW9uOm5vbmUiPkR5bWFudC5jb208L3NwYW4-PC9hPiAtIDwvc3Bhbj48c3BhbiBzdHlsZT0iZm9udC1mYW1pbHk6J01haWFuZHJhIEdEJyxzYW5zLXNlcmlmO2NvbG9yOmJsYWNrIj4mbmJzcDs8YSBocmVmPSJtYWlsdG86ZGFrQGR5bWFudC5jb20iIHRhcmdldD0iX2JsYW5rIj48c3BhbiBzdHlsZT0iY29sb3I6YmxhY2siPmRha0BkeW1hbnQuY29tPC9zcGFuPjwvYT4gPC9zcGFuPjxzcGFuIHN0eWxlPSJmb250LXNpemU6MTFwdDtmb250LWZhbWlseTonTWFpYW5kcmEgR0QnLHNhbnMtc2VyaWY7Y29sb3I6YmxhY2siPisgY28gZm9uZGF0ZXVyIGR1IG1hZ2F6aW5lIGRpZ2l0YWwgV2ViICZhbXA7IEx1eGUgPGEgaHJlZj0iaHR0cDovL3d3dy53ZWJhbmRsdXhlLmNvbS9hLXByb3Bvcy8iIHRhcmdldD0iX2JsYW5rIj5odHRwOi8vd3d3LndlYmFuZGx1eGUuY29tL2EtcHJvcG9zLzwvYT48dT48L3U-PHU-PC91Pjwvc3Bhbj48L3A-PHAgY2xhc3M9Ik1zb05vcm1hbCI-PHNwYW4gc3R5bGU9ImZvbnQtc2l6ZToxMXB0O2ZvbnQtZmFtaWx5OidNYWlhbmRyYSBHRCcsc2Fucy1zZXJpZjtjb2xvcjpibGFjayI-QmllbiDDoCB2b3VzLDx1PjwvdT48dT48L3U-PC9zcGFuPjwvcD48cCBjbGFzcz0iTXNvTm9ybWFsIj48c3BhbiBzdHlsZT0iZm9udC1zaXplOjExcHQ7Zm9udC1mYW1pbHk6J01haWFuZHJhIEdEJyxzYW5zLXNlcmlmO2NvbG9yOmJsYWNrIj5HbEc8dT48L3U-PHU-PC91Pjwvc3Bhbj48L3A-PHAgY2xhc3M9Ik1zb05vcm1hbCI-PHNwYW4gc3R5bGU9ImZvbnQtc2l6ZToxMXB0O2ZvbnQtZmFtaWx5OkNhbGlicmksc2Fucy1zZXJpZjtjb2xvcjpyZ2IoMzEsNzMsMTI1KSI-PHU-PC91PiZuYnNwOzx1PjwvdT48L3NwYW4-PC9wPjxwIGNsYXNzPSJNc29Ob3JtYWwiPjxzcGFuIHN0eWxlPSJmb250LXNpemU6MTFwdDtmb250LWZhbWlseTpDYWxpYnJpLHNhbnMtc2VyaWY7Y29sb3I6cmdiKDMxLDczLDEyNSkiPjx1PjwvdT4mbmJzcDs8dT48L3U-PC9zcGFuPjwvcD48ZGl2IHN0eWxlPSJib3JkZXItc3R5bGU6c29saWQgbm9uZSBub25lO2JvcmRlci10b3AtY29sb3I6cmdiKDE4MSwxOTYsMjIzKTtib3JkZXItdG9wLXdpZHRoOjFwdDtwYWRkaW5nOjNwdCAwY20gMGNtIj48cCBjbGFzcz0iTXNvTm9ybWFsIj48Yj48c3BhbiBzdHlsZT0iZm9udC1zaXplOjEwcHQ7Zm9udC1mYW1pbHk6VGFob21hLHNhbnMtc2VyaWYiPkRlJm5ic3A7Ojwvc3Bhbj48L2I-PHNwYW4gc3R5bGU9ImZvbnQtc2l6ZToxMHB0O2ZvbnQtZmFtaWx5OlRhaG9tYSxzYW5zLXNlcmlmIj4gQXJsZW5lIEJlbnRvbGlsYSBbbWFpbHRvOjxhIGhyZWY9Im1haWx0bzphcmxlbmViZW50b2xpbGFAZ21haWwuY29tIiB0YXJnZXQ9Il9ibGFuayI-YXJsZW5lYmVudG9saWxhQGdtYWlsLmNvbTwvYT5dIDxicj48Yj5FbnZvecOpJm5ic3A7OjwvYj4gdmVuZHJlZGkgMTkgZMOpY2VtYnJlIDIwMTQgMTk6MTg8YnI-PGI-w4AmbmJzcDs6PC9iPiA8YSBocmVmPSJtYWlsdG86Z2hpc2xhaW5lLmxlZ291Z3VlY0BlZGNwYXJpcy5lZHUiIHRhcmdldD0iX2JsYW5rIj5naGlzbGFpbmUubGVnb3VndWVjQGVkY3BhcmlzLmVkdTwvYT48YnI-PGI-Q2MmbmJzcDs6PC9iPiA8YSBocmVmPSJtYWlsdG86dGhpYmF1dC5kZWxhcml2aWVyZUBlZGNwYXJpcy5lZHUiIHRhcmdldD0iX2JsYW5rIj50aGliYXV0LmRlbGFyaXZpZXJlQGVkY3BhcmlzLmVkdTwvYT48YnI-PGI-T2JqZXQmbmJzcDs6PC9iPiBTdWpldCBkZSBtw6ltb2lyZSB1bmlxdWUgQXJsw6huZSBldCAiZXhlcmNpY2UiIDogamUgdmV1eCBkw6ltb250cmVyIHF1ZTx1PjwvdT48dT48L3U-PC9zcGFuPjwvcD48L2Rpdj48ZGl2PjxkaXY-PHAgY2xhc3M9Ik1zb05vcm1hbCI-PHU-PC91PiZuYnNwOzx1PjwvdT48L3A-PGRpdj48cCBjbGFzcz0iTXNvTm9ybWFsIj5DaGVycyB0b3VzPHU-PC91Pjx1PjwvdT48L3A-PGRpdj48cCBjbGFzcz0iTXNvTm9ybWFsIj48dT48L3U-Jm5ic3A7PHU-PC91PjwvcD48L2Rpdj48ZGl2PjxwIGNsYXNzPSJNc29Ob3JtYWwiPkonYWkgcmVwZW5zw6kgbW9uIHN1amV0IGRlIG3DqW1vaXJlIGVuIGZvbmN0aW9uIGRlIG1lcyBnb8O7dHMsIGRlIG1lcyBjb21ww6l0ZW5jZXMgZXQgZGUgbWVzIG9iamVjdGlmcyBwcm9mZXNzaW9ubmVscy4mbmJzcDs8dT48L3U-PHU-PC91PjwvcD48L2Rpdj48ZGl2PjxwIGNsYXNzPSJNc29Ob3JtYWwiPjx1PjwvdT4mbmJzcDs8dT48L3U-PC9wPjwvZGl2PjxkaXY-PHAgY2xhc3M9Ik1zb05vcm1hbCI-SmUgcGFycyBkb25jIHN1ciBsYSB2ZXJzaW9uIHF1ZSB2b3VzIGTDqWNvdXZyaXJleiBlbiBwacOoY2Ugam9pbnRlIGV0IHF1aSBwb3J0ZSBzdXIgbGVzIGVuamV1eCBkdSBkaWdpdGFsIGRhbnMgbGVzIHN0cmF0w6lnaWVzIGRlIGTDqXZlbG9wcGVtZW50IGR1IGx1eGUgZW4gbWF0acOocmUgZCdvZmZyZSwgZGUgc2VydmljZSwgZGUgZGlzdHJpYnV0aW9uIGV0IGRlIGNvbW11bmljYXRpb24uJm5ic3A7PHU-PC91Pjx1PjwvdT48L3A-PC9kaXY-PGRpdj48cCBjbGFzcz0iTXNvTm9ybWFsIj5KZSBtZSBzdWlzIMOpZ2FsZW1lbnQgcHLDqnTDqWUgYXUgbsOpY2Vzc2FpcmUgZXhlcmNpY2UgZHUgOiAmbmJzcDsiamUgdmV1eCBkw6ltb250cmVyIHF1ZSIuPHU-PC91Pjx1PjwvdT48L3A-PC9kaXY-PGRpdj48cCBjbGFzcz0iTXNvTm9ybWFsIj48dT48L3U-Jm5ic3A7PHU-PC91PjwvcD48L2Rpdj48ZGl2PjxwIGNsYXNzPSJNc29Ob3JtYWwiPkplIHJlc3RlIMOgIHZvdHJlIMOpY291dGUgcG91ciBmaW5hbGlzZXIgY2V0dGUgZmljaGUgcMOpZGFnb2dpcXVlIGV0IHZhbGlkZXIgbW9uIHN1amV0IGRlIG3DqW1vaXJlIGF2YW50IGxhIHJlbnRyw6llIGRlIGphbnZpZXIgc2kgY2VsYSB2b3VzIGVzdCBwb3NzaWJsZS4gSmUgdmFpcyBkJ29yZXMgZXQgZMOpasOgIGNvbW1lbmNlciBtZXMgcmVjaGVyY2hlcyBldCBmYWlyZSB1bmUgw6liYXVjaGUgZGUgcGxhbiBwZW5kYW50IGNlcyB2YWNhbmNlcy4mbmJzcDs8dT48L3U-PHU-PC91PjwvcD48L2Rpdj48ZGl2PjxwIGNsYXNzPSJNc29Ob3JtYWwiPjx1PjwvdT4mbmJzcDs8dT48L3U-PC9wPjwvZGl2PjxkaXY-PHAgY2xhc3M9Ik1zb05vcm1hbCI-SmUgdm91cyBzb3VoYWl0ZSBkZSB0csOocyBib25uZXMgZsOqdGVzLjx1PjwvdT48dT48L3U-PC9wPjwvZGl2PjxkaXY-PHAgY2xhc3M9Ik1zb05vcm1hbCI-PHU-PC91PiZuYnNwOzx1PjwvdT48L3A-PC9kaXY-PGRpdj48cCBjbGFzcz0iTXNvTm9ybWFsIj5CaWVuIMOgIHZvdXMsPHU-PC91Pjx1PjwvdT48L3A-PC9kaXY-PGRpdj48cCBjbGFzcz0iTXNvTm9ybWFsIj48dT48L3U-Jm5ic3A7PHU-PC91PjwvcD48L2Rpdj48ZGl2PjxwIGNsYXNzPSJNc29Ob3JtYWwiPkFybMOobmU8dT48L3U-PHU-PC91PjwvcD48L2Rpdj48L2Rpdj48L2Rpdj48L2Rpdj48L2Rpdj4NCjxicj48YnI-PC9kaXY-PC9kaXY-PGJyPjwvZGl2Pg0KPC9ibG9ja3F1b3RlPjwvZGl2Pjxicj48L2Rpdj4NCjwvZGl2PjwvYmxvY2txdW90ZT48L2JvZHk-PC9odG1sPg=="}}]}, :sizeEstimate=>26532}.merge(params)
62 | end
63 |
64 |
65 | def test_to_reply_message(params = {})
66 | {:id=>"14aecf708ee65122", :threadId=>"14aecf708ee65122", :labelIds=>["INBOX", "IMPORTANT", "CATEGORY_PERSONAL", "UNREAD"], :snippet=>"coucou Julien Hobeika | Co-Founder & CEO Email: julien@juliedesk.com Tel: +33 6 63 33 17 55 Julie", :historyId=>"232755", :payload=>{:mimeType=>"multipart/alternative", :filename=>"", :headers=>[{:name=>"Delivered-To", :value=>"julie@juliedesk.com"}, {:name=>"Received", :value=>"by 10.64.89.39 with SMTP id bl7csp1888330ieb; Thu, 15 Jan 2015 01:40:21 -0800 (PST)"}, {:name=>"X-Received", :value=>"by 10.194.2.75 with SMTP id 11mr16697173wjs.78.1421314820755; Thu, 15 Jan 2015 01:40:20 -0800 (PST)"}, {:name=>"Return-Path", :value=>""}, {:name=>"Received", :value=>"from mail-wg0-f52.google.com (mail-wg0-f52.google.com. [74.125.82.52]) by mx.google.com with ESMTPS id cz7si1861265wjc.17.2015.01.15.01.40.19 for (version=TLSv1 cipher=ECDHE-RSA-RC4-SHA bits=128/128); Thu, 15 Jan 2015 01:40:20 -0800 (PST)"}, {:name=>"Received-SPF", :value=>"pass (google.com: domain of julien@wepopp.com designates 74.125.82.52 as permitted sender) client-ip=74.125.82.52;"}, {:name=>"Authentication-Results", :value=>"mx.google.com; spf=pass (google.com: domain of julien@wepopp.com designates 74.125.82.52 as permitted sender) smtp.mail=julien@wepopp.com"}, {:name=>"Received", :value=>"by mail-wg0-f52.google.com with SMTP id x12so13734359wgg.11 for ; Thu, 15 Jan 2015 01:40:19 -0800 (PST)"}, {:name=>"X-Google-DKIM-Signature", :value=>"v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20130820; h=x-gm-message-state:mime-version:from:date:message-id:subject:to:cc :content-type; bh=VX+NTBD3y6zC7y2eoK6dXfXslqvi6t2cSoTCjb3ydPE=; b=GJnt5rk9Ck0uf9drEbY8tmxHqEosl3+89TyqId0TMttNgmjhV+rTX5tGe1N1wbPS0o ZMl5zDe/A5GGd7PHa8ykZZwNv5GQn0cjMQIMs+nMyUTUCUYeioWirF3frDJ8siV7+EXF s+l5+8Ul3suVPTcg5+zoNGgTJu3mWBC4E+1KMbVLYNOZtOd5PEMJPCZuTu2/k8Vw0Iw6 8JG02sSAzWRxNJnUoCRrShTV7C+eNRehvI7utHGMrobP1chWb2qZgLvbwGnpo/eBceya XWo/bpd9OcAYhb0spf0M2pXJ6TL/fzYbplFj0Lj8sXfRphQJivUjUVj4F02Tty2HpQ+q 4kQw=="}, {:name=>"X-Gm-Message-State", :value=>"ALoCoQk6eM56sO2fhoPw1I+al4RvoL3xd/Mzo7nmPK4WlB/OUaOD0isPUduI2MUrEdZgQ8tty/AH"}, {:name=>"X-Received", :value=>"by 10.180.126.99 with SMTP id mx3mr17257983wib.66.1421314819809; Thu, 15 Jan 2015 01:40:19 -0800 (PST)"}, {:name=>"MIME-Version", :value=>"1.0"}, {:name=>"Received", :value=>"by 10.180.8.228 with HTTP; Thu, 15 Jan 2015 01:39:59 -0800 (PST)"}, {:name=>"From", :value=>"Julien Hobeika "}, {:name=>"Date", :value=>"Thu, 15 Jan 2015 10:39:59 +0100"}, {:name=>"Message-ID", :value=>""}, {:name=>"Subject", :value=>"test reply message"}, {:name=>"To", :value=>"Julie Desk , Julien Hobeika "}, {:name=>"Cc", :value=>"Julien Hobeika , Nicolas Marlier "}, {:name=>"Content-Type", :value=>"multipart/alternative; boundary=e89a8f8389d1f2fbe9050cada4ac"}], :body=>{:size=>0}, :parts=>[{:partId=>"0", :mimeType=>"text/plain", :filename=>"", :headers=>[{:name=>"Content-Type", :value=>"text/plain; charset=UTF-8"}, {:name=>"Content-Transfer-Encoding", :value=>"quoted-printable"}], :body=>{:size=>144, :data=>"Y291Y291DQoNCg0KKkp1bGllbiBIb2JlaWthIHwgQ28tRm91bmRlciAmIENFTypFbWFpbDoganVsaWVuQGp1bGllZGVzay5jb20NClRlbDogKzMzIDYgNjMgMzMgMTcgNTUNCg0KKkp1bGllIERlc2sqDQp3d3cuanVsaWVkZXNrLmNvbQ0KDQoNCuGQpw0K"}}, {:partId=>"1", :mimeType=>"text/html", :filename=>"", :headers=>[{:name=>"Content-Type", :value=>"text/html; charset=UTF-8"}, {:name=>"Content-Transfer-Encoding", :value=>"quoted-printable"}], :body=>{:size=>742, :data=>"PGRpdiBkaXI9Imx0ciI-Y291Y291PGJyIGNsZWFyPSJhbGwiPjxkaXY-PGRpdiBjbGFzcz0iZ21haWxfc2lnbmF0dXJlIj48ZGl2IGRpcj0ibHRyIj48cD48Yj5KdWxpZW4gSG9iZWlrYSB8IENvLUZvdW5kZXIgJmFtcDsgQ0VPPGJyPjwvYj5FbWFpbDrCoDxhIGhyZWY9Im1haWx0bzpqdWxpZW5AanVsaWVkZXNrLmNvbSIgdGFyZ2V0PSJfYmxhbmsiPmp1bGllbkBqdWxpZWRlc2suY29tPC9hPjxicj5UZWw6ICszMyA2IDYzIDMzIDE3IDU1PC9wPjxwPjxiPkp1bGllIERlc2s8L2I-PGI-PGJyPjwvYj48YSBocmVmPSJodHRwOi8vd3d3Lmp1bGllZGVzay5jb20vIiBzdHlsZT0iY29sb3I6cmdiKDE3LDg1LDIwNCk7Zm9udC1mYW1pbHk6SGVsdmV0aWNhIiB0YXJnZXQ9Il9ibGFuayI-d3d3Lmp1bGllZGVzay5jb208L2E-PGI-PGJyPjwvYj48L3A-PHA-PGJyPjwvcD48L2Rpdj48L2Rpdj48L2Rpdj4NCjxkaXYgaHNwYWNlPSJzdHJlYWstcHQtbWFyayIgc3R5bGU9Im1heC1oZWlnaHQ6MXB4Ij48aW1nIHN0eWxlPSJ3aWR0aDowcHg7IG1heC1oZWlnaHQ6MHB4OyIgc3JjPSJodHRwczovL21haWxmb29nYWUuYXBwc3BvdC5jb20vdD9zZW5kZXI9YWFuVnNhV1Z1UUhkbGNHOXdjQzVqYjIwJTNEJmFtcDt0eXBlPXplcm9jb250ZW50JmFtcDtndWlkPTBiMWRiODRkLTFmMTctNDE1MS05ZmE5LTUxMWNiYTg0ODAyMiI-PGZvbnQgY29sb3I9IiNmZmZmZmYiIHNpemU9IjEiPuGQpzwvZm9udD48L2Rpdj48L2Rpdj4NCg=="}}]}, :sizeEstimate=>3710}
67 | end
68 |
69 | def test_to_reply_message2(params = {}) #without delivered_to in headers
70 | {:id=>"14aecf708ee65122", :threadId=>"14aecf708ee65122", :labelIds=>["INBOX", "IMPORTANT", "CATEGORY_PERSONAL", "UNREAD"], :snippet=>"coucou Julien Hobeika | Co-Founder & CEO Email: julien@juliedesk.com Tel: +33 6 63 33 17 55 Julie", :historyId=>"232755", :payload=>{:mimeType=>"multipart/alternative", :filename=>"", :headers=>[{:name=>"Received", :value=>"by 10.64.89.39 with SMTP id bl7csp1888330ieb; Thu, 15 Jan 2015 01:40:21 -0800 (PST)"}, {:name=>"X-Received", :value=>"by 10.194.2.75 with SMTP id 11mr16697173wjs.78.1421314820755; Thu, 15 Jan 2015 01:40:20 -0800 (PST)"}, {:name=>"Return-Path", :value=>""}, {:name=>"Received", :value=>"from mail-wg0-f52.google.com (mail-wg0-f52.google.com. [74.125.82.52]) by mx.google.com with ESMTPS id cz7si1861265wjc.17.2015.01.15.01.40.19 for (version=TLSv1 cipher=ECDHE-RSA-RC4-SHA bits=128/128); Thu, 15 Jan 2015 01:40:20 -0800 (PST)"}, {:name=>"Received-SPF", :value=>"pass (google.com: domain of julien@wepopp.com designates 74.125.82.52 as permitted sender) client-ip=74.125.82.52;"}, {:name=>"Authentication-Results", :value=>"mx.google.com; spf=pass (google.com: domain of julien@wepopp.com designates 74.125.82.52 as permitted sender) smtp.mail=julien@wepopp.com"}, {:name=>"Received", :value=>"by mail-wg0-f52.google.com with SMTP id x12so13734359wgg.11 for ; Thu, 15 Jan 2015 01:40:19 -0800 (PST)"}, {:name=>"X-Google-DKIM-Signature", :value=>"v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20130820; h=x-gm-message-state:mime-version:from:date:message-id:subject:to:cc :content-type; bh=VX+NTBD3y6zC7y2eoK6dXfXslqvi6t2cSoTCjb3ydPE=; b=GJnt5rk9Ck0uf9drEbY8tmxHqEosl3+89TyqId0TMttNgmjhV+rTX5tGe1N1wbPS0o ZMl5zDe/A5GGd7PHa8ykZZwNv5GQn0cjMQIMs+nMyUTUCUYeioWirF3frDJ8siV7+EXF s+l5+8Ul3suVPTcg5+zoNGgTJu3mWBC4E+1KMbVLYNOZtOd5PEMJPCZuTu2/k8Vw0Iw6 8JG02sSAzWRxNJnUoCRrShTV7C+eNRehvI7utHGMrobP1chWb2qZgLvbwGnpo/eBceya XWo/bpd9OcAYhb0spf0M2pXJ6TL/fzYbplFj0Lj8sXfRphQJivUjUVj4F02Tty2HpQ+q 4kQw=="}, {:name=>"X-Gm-Message-State", :value=>"ALoCoQk6eM56sO2fhoPw1I+al4RvoL3xd/Mzo7nmPK4WlB/OUaOD0isPUduI2MUrEdZgQ8tty/AH"}, {:name=>"X-Received", :value=>"by 10.180.126.99 with SMTP id mx3mr17257983wib.66.1421314819809; Thu, 15 Jan 2015 01:40:19 -0800 (PST)"}, {:name=>"MIME-Version", :value=>"1.0"}, {:name=>"Received", :value=>"by 10.180.8.228 with HTTP; Thu, 15 Jan 2015 01:39:59 -0800 (PST)"}, {:name=>"From", :value=>"Julien Hobeika "}, {:name=>"Date", :value=>"Thu, 15 Jan 2015 10:39:59 +0100"}, {:name=>"Message-ID", :value=>""}, {:name=>"Subject", :value=>"test reply message"}, {:name=>"To", :value=>"Julie Desk , Julien Hobeika "}, {:name=>"Cc", :value=>"Julien Hobeika , Nicolas Marlier "}, {:name=>"Content-Type", :value=>"multipart/alternative; boundary=e89a8f8389d1f2fbe9050cada4ac"}], :body=>{:size=>0}, :parts=>[{:partId=>"0", :mimeType=>"text/plain", :filename=>"", :headers=>[{:name=>"Content-Type", :value=>"text/plain; charset=UTF-8"}, {:name=>"Content-Transfer-Encoding", :value=>"quoted-printable"}], :body=>{:size=>144, :data=>"Y291Y291DQoNCg0KKkp1bGllbiBIb2JlaWthIHwgQ28tRm91bmRlciAmIENFTypFbWFpbDoganVsaWVuQGp1bGllZGVzay5jb20NClRlbDogKzMzIDYgNjMgMzMgMTcgNTUNCg0KKkp1bGllIERlc2sqDQp3d3cuanVsaWVkZXNrLmNvbQ0KDQoNCuGQpw0K"}}, {:partId=>"1", :mimeType=>"text/html", :filename=>"", :headers=>[{:name=>"Content-Type", :value=>"text/html; charset=UTF-8"}, {:name=>"Content-Transfer-Encoding", :value=>"quoted-printable"}], :body=>{:size=>742, :data=>"PGRpdiBkaXI9Imx0ciI-Y291Y291PGJyIGNsZWFyPSJhbGwiPjxkaXY-PGRpdiBjbGFzcz0iZ21haWxfc2lnbmF0dXJlIj48ZGl2IGRpcj0ibHRyIj48cD48Yj5KdWxpZW4gSG9iZWlrYSB8IENvLUZvdW5kZXIgJmFtcDsgQ0VPPGJyPjwvYj5FbWFpbDrCoDxhIGhyZWY9Im1haWx0bzpqdWxpZW5AanVsaWVkZXNrLmNvbSIgdGFyZ2V0PSJfYmxhbmsiPmp1bGllbkBqdWxpZWRlc2suY29tPC9hPjxicj5UZWw6ICszMyA2IDYzIDMzIDE3IDU1PC9wPjxwPjxiPkp1bGllIERlc2s8L2I-PGI-PGJyPjwvYj48YSBocmVmPSJodHRwOi8vd3d3Lmp1bGllZGVzay5jb20vIiBzdHlsZT0iY29sb3I6cmdiKDE3LDg1LDIwNCk7Zm9udC1mYW1pbHk6SGVsdmV0aWNhIiB0YXJnZXQ9Il9ibGFuayI-d3d3Lmp1bGllZGVzay5jb208L2E-PGI-PGJyPjwvYj48L3A-PHA-PGJyPjwvcD48L2Rpdj48L2Rpdj48L2Rpdj4NCjxkaXYgaHNwYWNlPSJzdHJlYWstcHQtbWFyayIgc3R5bGU9Im1heC1oZWlnaHQ6MXB4Ij48aW1nIHN0eWxlPSJ3aWR0aDowcHg7IG1heC1oZWlnaHQ6MHB4OyIgc3JjPSJodHRwczovL21haWxmb29nYWUuYXBwc3BvdC5jb20vdD9zZW5kZXI9YWFuVnNhV1Z1UUhkbGNHOXdjQzVqYjIwJTNEJmFtcDt0eXBlPXplcm9jb250ZW50JmFtcDtndWlkPTBiMWRiODRkLTFmMTctNDE1MS05ZmE5LTUxMWNiYTg0ODAyMiI-PGZvbnQgY29sb3I9IiNmZmZmZmYiIHNpemU9IjEiPuGQpzwvZm9udD48L2Rpdj48L2Rpdj4NCg=="}}]}, :sizeEstimate=>3710}
71 | end
72 |
73 | def test_reply_message(params = {})
74 | {body: "test"}
75 | end
76 |
77 | def test_forward_message
78 | {to: "julien@wepopp.com", bbc: "julien.hobeika@gmail.com", cc: "julien@juliedesk.com, nicolas@juliedesk.com", subject: "cool subject", body: "test"}
79 | end
80 |
81 | def test_forward_message_with_html
82 | {to: "julien@wepopp.com", bbc: "julien.hobeika@gmail.com", cc: "julien@juliedesk.com, nicolas@juliedesk.com", subject: "cool subject", text: "test", html: "test"}
83 | end
84 |
85 | def test_forwarded_message
86 | {:id=>"14aef32bd53a74bb", :threadId=>"14aecf708ee65122", :labelIds=>["SENT"], :snippet=>"test Thu, 15 Jan 2015 10:39:59 +0100 Julien Hobeika <julien@juliedesk.com>: >coucou >", :historyId=>"234207", :payload=>{:partId=>"", :mimeType=>"text/plain", :filename=>"", :headers=>[{:name=>"Received", :value=>"from 992877924458-i6nbjvo0fspv8hpmpss0i9aglneqrdpm.apps.googleusercontent.com named unknown by gmailapi.google.com with HTTPREST; Thu, 15 Jan 2015 12:04:47 -0800"}, {:name=>"Date", :value=>"Thu, 15 Jan 2015 12:04:47 -0800"}, {:name=>"To", :value=>"julien@wepopp.com"}, {:name=>"Cc", :value=>"julien@juliedesk.com, nicolas@juliedesk.com"}, {:name=>"Message-Id", :value=>""}, {:name=>"In-Reply-To", :value=>""}, {:name=>"References", :value=>""}, {:name=>"Subject", :value=>"cool subject"}, {:name=>"Mime-Version", :value=>"1.0"}, {:name=>"Content-Type", :value=>"text/plain; charset=UTF-8"}, {:name=>"Content-Transfer-Encoding", :value=>"quoted-printable"}, {:name=>"From", :value=>"julie@juliedesk.com"}], :body=>{:size=>238, :data=>"dGVzdA0KDQpUaHUsIDE1IEphbiAyMDE1IDEwOjM5OjU5ICswMTAwIEp1bGllbiBIb2JlaWthIDxqdWxpZW5AanVsaWVkZXNrLmNvbT46DQoNCj5jb3Vjb3UNCj4NCj4NCj4qSnVsaWVuIEhvYmVpa2EgfCBDby1Gb3VuZGVyICYgQ0VPKkVtYWlsOiBqdWxpZW5AanVsaWVkZXNrLmNvbQ0KPlRlbDogKzMzIDYgNjMgMzMgMTcgNTUNCj4NCj4qSnVsaWUgRGVzayoNCj53d3cuanVsaWVkZXNrLmNvbQ0KPg0KPg0KPuGQpw0KPg=="}}, :sizeEstimate=>948}
87 | end
88 |
89 |
90 | def test_forwarded_message_with_html
91 | {:id=>"14aef33bfcd19656", :threadId=>"14aecf708ee65122", :labelIds=>["SENT"], :snippet=>"test Thu, 15 Jan 2015 10:39:59 +0100 Julien Hobeika <julien@juliedesk.com>: coucou Julien", :historyId=>"234237", :payload=>{:mimeType=>"multipart/alternative", :filename=>"", :headers=>[{:name=>"Received", :value=>"from 992877924458-i6nbjvo0fspv8hpmpss0i9aglneqrdpm.apps.googleusercontent.com named unknown by gmailapi.google.com with HTTPREST; Thu, 15 Jan 2015 12:05:53 -0800"}, {:name=>"Date", :value=>"Thu, 15 Jan 2015 12:05:53 -0800"}, {:name=>"To", :value=>"julien@wepopp.com"}, {:name=>"Cc", :value=>"julien@juliedesk.com, nicolas@juliedesk.com"}, {:name=>"Message-Id", :value=>""}, {:name=>"In-Reply-To", :value=>""}, {:name=>"References", :value=>""}, {:name=>"Subject", :value=>"cool subject"}, {:name=>"Mime-Version", :value=>"1.0"}, {:name=>"Content-Type", :value=>"multipart/alternative; boundary=\"--==_mimepart_54b81da0a179_d3733fe0444541d8958c\"; charset=UTF-8"}, {:name=>"Content-Transfer-Encoding", :value=>"7bit"}, {:name=>"From", :value=>"julie@juliedesk.com"}], :body=>{:size=>0}, :parts=>[{:partId=>"0", :mimeType=>"text/plain", :filename=>"", :headers=>[{:name=>"Content-Type", :value=>"text/plain; charset=UTF-8"}, {:name=>"Content-Transfer-Encoding", :value=>"quoted-printable"}], :body=>{:size=>238, :data=>"dGVzdA0KDQpUaHUsIDE1IEphbiAyMDE1IDEwOjM5OjU5ICswMTAwIEp1bGllbiBIb2JlaWthIDxqdWxpZW5AanVsaWVkZXNrLmNvbT46DQoNCj5jb3Vjb3UNCj4NCj4NCj4qSnVsaWVuIEhvYmVpa2EgfCBDby1Gb3VuZGVyICYgQ0VPKkVtYWlsOiBqdWxpZW5AanVsaWVkZXNrLmNvbQ0KPlRlbDogKzMzIDYgNjMgMzMgMTcgNTUNCj4NCj4qSnVsaWUgRGVzayoNCj53d3cuanVsaWVkZXNrLmNvbQ0KPg0KPg0KPuGQpw0KPg=="}}, {:partId=>"1", :mimeType=>"text/html", :filename=>"", :headers=>[{:name=>"Content-Type", :value=>"text/html; charset=UTF-8"}, {:name=>"Content-Transfer-Encoding", :value=>"quoted-printable"}], :body=>{:size=>1005, :data=>"PGRpdj48Yj50ZXN0PC9iPjwvZGl2Pg0KPGJyPjxicj48ZGl2IGNsYXNzPSJnbWFpbF9xdW90ZSI-IFRodSwgMTUgSmFuIDIwMTUgMTA6Mzk6NTkgKzAxMDAgSnVsaWVuIEhvYmVpa2EgJmx0O2p1bGllbkBqdWxpZWRlc2suY29tJmd0Ozo8YnI-PGJsb2NrcXVvdGUgY2xhc3M9ImdtYWlsX3F1b3RlIiBzdHlsZT0ibWFyZ2luOjAgMCAwIC44ZXg7Ym9yZGVyLWxlZnQ6MXB4ICNjY2Mgc29saWQ7cGFkZGluZy1sZWZ0OjFleCI-PGRpdiBkaXI9Imx0ciI-Y291Y291PGJyIGNsZWFyPSJhbGwiPjxkaXY-PGRpdiBjbGFzcz0iZ21haWxfc2lnbmF0dXJlIj48ZGl2IGRpcj0ibHRyIj48cD48Yj5KdWxpZW4gSG9iZWlrYSB8IENvLUZvdW5kZXIgJmFtcDsgQ0VPPGJyPjwvYj5FbWFpbDrCoDxhIGhyZWY9Im1haWx0bzpqdWxpZW5AanVsaWVkZXNrLmNvbSIgdGFyZ2V0PSJfYmxhbmsiPmp1bGllbkBqdWxpZWRlc2suY29tPC9hPjxicj5UZWw6ICszMyA2IDYzIDMzIDE3IDU1PC9wPjxwPjxiPkp1bGllIERlc2s8L2I-PGI-PGJyPjwvYj48YSBocmVmPSJodHRwOi8vd3d3Lmp1bGllZGVzay5jb20vIiBzdHlsZT0iY29sb3I6cmdiKDE3LDg1LDIwNCk7Zm9udC1mYW1pbHk6SGVsdmV0aWNhIiB0YXJnZXQ9Il9ibGFuayI-d3d3Lmp1bGllZGVzay5jb208L2E-PGI-PGJyPjwvYj48L3A-PHA-PGJyPjwvcD48L2Rpdj48L2Rpdj48L2Rpdj4NCjxkaXYgaHNwYWNlPSJzdHJlYWstcHQtbWFyayIgc3R5bGU9Im1heC1oZWlnaHQ6MXB4Ij48aW1nIHN0eWxlPSJ3aWR0aDowcHg7IG1heC1oZWlnaHQ6MHB4OyIgc3JjPSJodHRwczovL21haWxmb29nYWUuYXBwc3BvdC5jb20vdD9zZW5kZXI9YWFuVnNhV1Z1UUhkbGNHOXdjQzVqYjIwJTNEJmFtcDt0eXBlPXplcm9jb250ZW50JmFtcDtndWlkPTBiMWRiODRkLTFmMTctNDE1MS05ZmE5LTUxMWNiYTg0ODAyMiI-PGZvbnQgY29sb3I9IiNmZmZmZmYiIHNpemU9IjEiPuGQpzwvZm9udD48L2Rpdj48L2Rpdj4NCjwvYmxvY2txdW90ZT48L2Rpdj48YnI-"}}]}, :sizeEstimate=>2448}
92 | end
93 |
94 | def test_reply_message_with_html(params = {})
95 | {html: "test", text: "test"}
96 | end
97 |
98 | def test_replied_message(params = {})
99 | {:id=>"14aecf9e31d945ba", :threadId=>"14aecf708ee65122", :labelIds=>["SENT", "INBOX", "UNREAD"], :snippet=>"test Thu, 15 Jan 2015 10:39:59 +0100 Julien Hobeika <julien@juliedesk.com>: >coucou >", :historyId=>"232799", :payload=>{:partId=>"", :mimeType=>"text/plain", :filename=>"", :headers=>[{:name=>"Received", :value=>"from 992877924458-i6nbjvo0fspv8hpmpss0i9aglneqrdpm.apps.googleusercontent.com named unknown by gmailapi.google.com with HTTPREST; Thu, 15 Jan 2015 01:43:27 -0800"}, {:name=>"Date", :value=>"Thu, 15 Jan 2015 01:43:27 -0800"}, {:name=>"To", :value=>"Julien Hobeika "}, {:name=>"Cc", :value=>"Julien Hobeika , Julien Hobeika , Nicolas Marlier "}, {:name=>"Message-Id", :value=>""}, {:name=>"In-Reply-To", :value=>""}, {:name=>"References", :value=>""}, {:name=>"Subject", :value=>"test reply message"}, {:name=>"Mime-Version", :value=>"1.0"}, {:name=>"Content-Type", :value=>"text/plain; charset=UTF-8"}, {:name=>"Content-Transfer-Encoding", :value=>"quoted-printable"}, {:name=>"From", :value=>"julie@juliedesk.com"}], :body=>{:size=>238, :data=>"dGVzdA0KDQpUaHUsIDE1IEphbiAyMDE1IDEwOjM5OjU5ICswMTAwIEp1bGllbiBIb2JlaWthIDxqdWxpZW5AanVsaWVkZXNrLmNvbT46DQoNCj5jb3Vjb3UNCj4NCj4NCj4qSnVsaWVuIEhvYmVpa2EgfCBDby1Gb3VuZGVyICYgQ0VPKkVtYWlsOiBqdWxpZW5AanVsaWVkZXNrLmNvbQ0KPlRlbDogKzMzIDYgNjMgMzMgMTcgNTUNCj4NCj4qSnVsaWUgRGVzayoNCj53d3cuanVsaWVkZXNrLmNvbQ0KPg0KPg0KPuGQpw0KPg=="}}, :sizeEstimate=>1089}
100 | end
101 |
102 |
103 | def test_replied_message_with_html(params = {})
104 | {:id=>"14aef0d08d39b4df", :threadId=>"14aecf708ee65122", :labelIds=>["SENT", "INBOX", "UNREAD"], :snippet=>"test Thu, 15 Jan 2015 10:39:59 +0100 Julien Hobeika <julien@juliedesk.com>: coucou Julien", :historyId=>"234054", :payload=>{:mimeType=>"multipart/alternative", :filename=>"", :headers=>[{:name=>"Received", :value=>"from 992877924458-i6nbjvo0fspv8hpmpss0i9aglneqrdpm.apps.googleusercontent.com named unknown by gmailapi.google.com with HTTPREST; Thu, 15 Jan 2015 11:23:36 -0800"}, {:name=>"Date", :value=>"Thu, 15 Jan 2015 11:23:36 -0800"}, {:name=>"To", :value=>"Julien Hobeika "}, {:name=>"Cc", :value=>"Julien Hobeika , Julien Hobeika , Nicolas Marlier "}, {:name=>"Message-Id", :value=>""}, {:name=>"In-Reply-To", :value=>""}, {:name=>"References", :value=>""}, {:name=>"Subject", :value=>"test reply message"}, {:name=>"Mime-Version", :value=>"1.0"}, {:name=>"Content-Type", :value=>"multipart/alternative; boundary=\"--==_mimepart_54b813b749eaa_d0963fc7bc45c1d0581fa\"; charset=UTF-8"}, {:name=>"Content-Transfer-Encoding", :value=>"7bit"}, {:name=>"From", :value=>"julie@juliedesk.com"}], :body=>{:size=>0}, :parts=>[{:partId=>"0", :mimeType=>"text/plain", :filename=>"", :headers=>[{:name=>"Content-Type", :value=>"text/plain; charset=UTF-8"}, {:name=>"Content-Transfer-Encoding", :value=>"quoted-printable"}], :body=>{:size=>238, :data=>"dGVzdA0KDQpUaHUsIDE1IEphbiAyMDE1IDEwOjM5OjU5ICswMTAwIEp1bGllbiBIb2JlaWthIDxqdWxpZW5AanVsaWVkZXNrLmNvbT46DQoNCj5jb3Vjb3UNCj4NCj4NCj4qSnVsaWVuIEhvYmVpa2EgfCBDby1Gb3VuZGVyICYgQ0VPKkVtYWlsOiBqdWxpZW5AanVsaWVkZXNrLmNvbQ0KPlRlbDogKzMzIDYgNjMgMzMgMTcgNTUNCj4NCj4qSnVsaWUgRGVzayoNCj53d3cuanVsaWVkZXNrLmNvbQ0KPg0KPg0KPuGQpw0KPg=="}}, {:partId=>"1", :mimeType=>"text/html", :filename=>"", :headers=>[{:name=>"Content-Type", :value=>"text/html; charset=UTF-8"}, {:name=>"Content-Transfer-Encoding", :value=>"quoted-printable"}], :body=>{:size=>1005, :data=>"PGRpdj48Yj50ZXN0PC9iPjwvZGl2Pg0KPGJyPjxicj48ZGl2IGNsYXNzPSJnbWFpbF9xdW90ZSI-IFRodSwgMTUgSmFuIDIwMTUgMTA6Mzk6NTkgKzAxMDAgSnVsaWVuIEhvYmVpa2EgJmx0O2p1bGllbkBqdWxpZWRlc2suY29tJmd0Ozo8YnI-PGJsb2NrcXVvdGUgY2xhc3M9ImdtYWlsX3F1b3RlIiBzdHlsZT0ibWFyZ2luOjAgMCAwIC44ZXg7Ym9yZGVyLWxlZnQ6MXB4ICNjY2Mgc29saWQ7cGFkZGluZy1sZWZ0OjFleCI-PGRpdiBkaXI9Imx0ciI-Y291Y291PGJyIGNsZWFyPSJhbGwiPjxkaXY-PGRpdiBjbGFzcz0iZ21haWxfc2lnbmF0dXJlIj48ZGl2IGRpcj0ibHRyIj48cD48Yj5KdWxpZW4gSG9iZWlrYSB8IENvLUZvdW5kZXIgJmFtcDsgQ0VPPGJyPjwvYj5FbWFpbDrCoDxhIGhyZWY9Im1haWx0bzpqdWxpZW5AanVsaWVkZXNrLmNvbSIgdGFyZ2V0PSJfYmxhbmsiPmp1bGllbkBqdWxpZWRlc2suY29tPC9hPjxicj5UZWw6ICszMyA2IDYzIDMzIDE3IDU1PC9wPjxwPjxiPkp1bGllIERlc2s8L2I-PGI-PGJyPjwvYj48YSBocmVmPSJodHRwOi8vd3d3Lmp1bGllZGVzay5jb20vIiBzdHlsZT0iY29sb3I6cmdiKDE3LDg1LDIwNCk7Zm9udC1mYW1pbHk6SGVsdmV0aWNhIiB0YXJnZXQ9Il9ibGFuayI-d3d3Lmp1bGllZGVzay5jb208L2E-PGI-PGJyPjwvYj48L3A-PHA-PGJyPjwvcD48L2Rpdj48L2Rpdj48L2Rpdj4NCjxkaXYgaHNwYWNlPSJzdHJlYWstcHQtbWFyayIgc3R5bGU9Im1heC1oZWlnaHQ6MXB4Ij48aW1nIHN0eWxlPSJ3aWR0aDowcHg7IG1heC1oZWlnaHQ6MHB4OyIgc3JjPSJodHRwczovL21haWxmb29nYWUuYXBwc3BvdC5jb20vdD9zZW5kZXI9YWFuVnNhV1Z1UUhkbGNHOXdjQzVqYjIwJTNEJmFtcDt0eXBlPXplcm9jb250ZW50JmFtcDtndWlkPTBiMWRiODRkLTFmMTctNDE1MS05ZmE5LTUxMWNiYTg0ODAyMiI-PGZvbnQgY29sb3I9IiNmZmZmZmYiIHNpemU9IjEiPuGQpzwvZm9udD48L2Rpdj48L2Rpdj4NCjwvYmxvY2txdW90ZT48L2Rpdj48YnI-"}}]}, :sizeEstimate=>2597}
105 | end
106 |
107 |
108 |
109 | def test_unread_message(params = {})
110 | {:id=>"14aecf9e31d945ba", :threadId=>"14aecf708ee65122", :labelIds=>["IMPORTANT", "CATEGORY_PERSONAL","UNREAD"], :snippet=>"test Thu, 15 Jan 2015 10:39:59 +0100 Julien Hobeika <julien@juliedesk.com>: >coucou >", :historyId=>"232799", :payload=>{:partId=>"", :mimeType=>"text/plain", :filename=>"", :headers=>[{:name=>"Received", :value=>"from 992877924458-i6nbjvo0fspv8hpmpss0i9aglneqrdpm.apps.googleusercontent.com named unknown by gmailapi.google.com with HTTPREST; Thu, 15 Jan 2015 01:43:27 -0800"}, {:name=>"Date", :value=>"Thu, 15 Jan 2015 01:43:27 -0800"}, {:name=>"To", :value=>"Julien Hobeika "}, {:name=>"Cc", :value=>"Julien Hobeika , Julien Hobeika , Nicolas Marlier "}, {:name=>"Message-Id", :value=>""}, {:name=>"In-Reply-To", :value=>""}, {:name=>"References", :value=>""}, {:name=>"Subject", :value=>"test reply message"}, {:name=>"Mime-Version", :value=>"1.0"}, {:name=>"Content-Type", :value=>"text/plain; charset=UTF-8"}, {:name=>"Content-Transfer-Encoding", :value=>"quoted-printable"}, {:name=>"From", :value=>"julie@juliedesk.com"}], :body=>{:size=>238, :data=>"dGVzdA0KDQpUaHUsIDE1IEphbiAyMDE1IDEwOjM5OjU5ICswMTAwIEp1bGllbiBIb2JlaWthIDxqdWxpZW5AanVsaWVkZXNrLmNvbT46DQoNCj5jb3Vjb3UNCj4NCj4NCj4qSnVsaWVuIEhvYmVpa2EgfCBDby1Gb3VuZGVyICYgQ0VPKkVtYWlsOiBqdWxpZW5AanVsaWVkZXNrLmNvbQ0KPlRlbDogKzMzIDYgNjMgMzMgMTcgNTUNCj4NCj4qSnVsaWUgRGVzayoNCj53d3cuanVsaWVkZXNrLmNvbQ0KPg0KPg0KPuGQpw0KPg=="}}, :sizeEstimate=>1089}
111 | end
112 |
113 | def test_sent_message(params = {})
114 | {:id=>"14aecf9e31d945ba", :threadId=>"14aecf708ee65122", :labelIds=>["IMPORTANT", "CATEGORY_PERSONAL","SENT"], :snippet=>"test Thu, 15 Jan 2015 10:39:59 +0100 Julien Hobeika <julien@juliedesk.com>: >coucou >", :historyId=>"232799", :payload=>{:partId=>"", :mimeType=>"text/plain", :filename=>"", :headers=>[{:name=>"Received", :value=>"from 992877924458-i6nbjvo0fspv8hpmpss0i9aglneqrdpm.apps.googleusercontent.com named unknown by gmailapi.google.com with HTTPREST; Thu, 15 Jan 2015 01:43:27 -0800"}, {:name=>"Date", :value=>"Thu, 15 Jan 2015 01:43:27 -0800"}, {:name=>"To", :value=>"Julien Hobeika "}, {:name=>"Cc", :value=>"Julien Hobeika , Julien Hobeika , Nicolas Marlier "}, {:name=>"Message-Id", :value=>""}, {:name=>"In-Reply-To", :value=>""}, {:name=>"References", :value=>""}, {:name=>"Subject", :value=>"test reply message"}, {:name=>"Mime-Version", :value=>"1.0"}, {:name=>"Content-Type", :value=>"text/plain; charset=UTF-8"}, {:name=>"Content-Transfer-Encoding", :value=>"quoted-printable"}, {:name=>"From", :value=>"julie@juliedesk.com"}], :body=>{:size=>238, :data=>"dGVzdA0KDQpUaHUsIDE1IEphbiAyMDE1IDEwOjM5OjU5ICswMTAwIEp1bGllbiBIb2JlaWthIDxqdWxpZW5AanVsaWVkZXNrLmNvbT46DQoNCj5jb3Vjb3UNCj4NCj4NCj4qSnVsaWVuIEhvYmVpa2EgfCBDby1Gb3VuZGVyICYgQ0VPKkVtYWlsOiBqdWxpZW5AanVsaWVkZXNrLmNvbQ0KPlRlbDogKzMzIDYgNjMgMzMgMTcgNTUNCj4NCj4qSnVsaWUgRGVzayoNCj53d3cuanVsaWVkZXNrLmNvbQ0KPg0KPg0KPuGQpw0KPg=="}}, :sizeEstimate=>1089}
115 | end
116 |
117 | def test_inbox_message(params = {})
118 | {:id=>"14aecf9e31d945ba", :threadId=>"14aecf708ee65122", :labelIds=>["IMPORTANT", "CATEGORY_PERSONAL","INBOX"], :snippet=>"test Thu, 15 Jan 2015 10:39:59 +0100 Julien Hobeika <julien@juliedesk.com>: >coucou >", :historyId=>"232799", :payload=>{:partId=>"", :mimeType=>"text/plain", :filename=>"", :headers=>[{:name=>"Received", :value=>"from 992877924458-i6nbjvo0fspv8hpmpss0i9aglneqrdpm.apps.googleusercontent.com named unknown by gmailapi.google.com with HTTPREST; Thu, 15 Jan 2015 01:43:27 -0800"}, {:name=>"Date", :value=>"Thu, 15 Jan 2015 01:43:27 -0800"}, {:name=>"To", :value=>"Julien Hobeika "}, {:name=>"Cc", :value=>"Julien Hobeika , Julien Hobeika , Nicolas Marlier "}, {:name=>"Message-Id", :value=>""}, {:name=>"In-Reply-To", :value=>""}, {:name=>"References", :value=>""}, {:name=>"Subject", :value=>"test reply message"}, {:name=>"Mime-Version", :value=>"1.0"}, {:name=>"Content-Type", :value=>"text/plain; charset=UTF-8"}, {:name=>"Content-Transfer-Encoding", :value=>"quoted-printable"}, {:name=>"From", :value=>"julie@juliedesk.com"}], :body=>{:size=>238, :data=>"dGVzdA0KDQpUaHUsIDE1IEphbiAyMDE1IDEwOjM5OjU5ICswMTAwIEp1bGllbiBIb2JlaWthIDxqdWxpZW5AanVsaWVkZXNrLmNvbT46DQoNCj5jb3Vjb3UNCj4NCj4NCj4qSnVsaWVuIEhvYmVpa2EgfCBDby1Gb3VuZGVyICYgQ0VPKkVtYWlsOiBqdWxpZW5AanVsaWVkZXNrLmNvbQ0KPlRlbDogKzMzIDYgNjMgMzMgMTcgNTUNCj4NCj4qSnVsaWUgRGVzayoNCj53d3cuanVsaWVkZXNrLmNvbQ0KPg0KPg0KPuGQpw0KPg=="}}, :sizeEstimate=>1089}
119 | end
120 |
121 | def test_message_list
122 | {:messages=>[{:id=>"14ae456f2ff1e3e4", :threadId=>"14ae456f2ff1e3e4"}, {:id=>"14ae456891f20924", :threadId=>"14ae4438ed604170"}, {:id=>"14ae455204ed507e", :threadId=>"14ae4438ed604170"}, {:id=>"14ae45432aaf0c5a", :threadId=>"14ae4438ed604170"}, {:id=>"14ae4438ed604170", :threadId=>"14ae4438ed604170"}], :nextPageToken=>"05968490989102563512", :resultSizeEstimate=>20}
123 | end
124 |
125 |
126 | end
127 | end
--------------------------------------------------------------------------------
/test/test_helper.rb:
--------------------------------------------------------------------------------
1 | require 'gmail'
2 | require 'test/unit'
3 | require 'mocha/setup'
4 | require 'stringio'
5 | require 'shoulda'
6 | require File.expand_path('../test_data', __FILE__)
7 |
8 | # monkeypatch request methods
9 | module Gmail
10 | @client = nil
11 |
12 | def self.connect
13 |
14 | end
15 |
16 | def self.client= value
17 | @client = value
18 | end
19 |
20 | end
21 |
22 | class Test::Unit::TestCase
23 | include Gmail::TestData
24 | include Mocha
25 |
26 | setup do
27 | @mock = mock
28 | Gmail.client = @mock
29 | Gmail.new(client_id: "foo", client_secret: "foo", refresh_token: "foo", application_name: "test", application_version: "test")
30 | end
31 |
32 | teardown do
33 | Gmail.client = nil
34 | Gmail.client_id = nil
35 | Gmail.client_secret = nil
36 | Gmail.refresh_token = nil
37 | end
38 | end
--------------------------------------------------------------------------------