2017-11-08
Введение.
Gmail API является RESTful API, которое можно использовать для доступа к почтовым сообщениям пользователя и отправлять электронные сообщения. Для большинства веб приложений (включая мобильные приложения), Gmail API является лучшим выбором для авторизованного доступа к пользовательским данным Gmail.
Gmail API дает вам гибкий RESTful доступ к пользовательскому почтовому ящику с естественным интерфейсом к Threads, Messages, Labels, Drafts, History, и Settings
. Этот интерфейс реализован на многих современных языках программирования. Ваше приложение может использовать это API, чтобы опеспечить следущие возможности Gmail:
- Читать сообщения с Gmail;
- Передавать email сообщения;
- Поиск соответствующих сообщений;
- Создавать фильтры для автоматической маркировки, пересылки или архивирования сообщений.
Все что вам необходимо чтобы использовать Gmail API - это выбрать клиенскую библиотеку для вашего языка программирования и ваше приложение должно уметь авторизировать пользователя Gmail.
Пример использования Gmail API на GitHub можно посмотреть здесь
Ресурсы
Загрузка/Инициализация библиотеки Google API
Вначале нужно загрузить и инициализировать клиенскую библиотеку Google API см. пр.1.
пр.1
...
/**
* Google Client load/init
* @param params (Object)
* etc. {
* apiKey: 'xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx',
* clientId: 'xxxxxxxxxxxx-xxxxxxxxxxxxxxxxxxxxxxx.apps.googleusercontent.com',
* discoveryDocs: ['https://www.googleapis.com/discovery/v1/apis/gmail/v1/rest'],
* scope: 'https://www.googleapis.com/auth/gmail.readonly https://www.googleapis.com/auth/gmail.send'
* }
* @return {Promise}
*/
loadClient (params) {
return new Promise(function (resolve, reject) {
_loadGoogleApi().then(function () {
if (debug) {
console.log('loadGoogleAPI - OK')
}
return _initClient(params)
}).then(function () {
if (debug) {
console.log('googleClient.init - OK')
}
// Load gmail library
window.gapi.client.load('gmail', 'v1', resolve)
})
})
}
/**
* Load google api
* @return {Promise}
* @private
*/
_loadGoogleApi () {
return new Promise(function (resolve, reject) {
const script = document.createElement('script')
script.src = 'https://apis.google.com/js/platform.js'
script.onreadystatechange = script.onload = function () {
if (!script.readyState || /loaded|complete/.test(script.readyState)) {
setTimeout(function () {
resolve()
}, 500)
}
}
document.getElementsByTagName('head')[0].appendChild(script)
})
}
/**
* Google client load/init
* @param params (Object)
* etc. {
* apiKey: 'xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx',
* clientId: 'xxxxxxxxxxxx-xxxxxxxxxxxxxxxxxxxxxxx.apps.googleusercontent.com',
* discoveryDocs: ['https://www.googleapis.com/discovery/v1/apis/gmail/v1/rest'],
* scope: 'https://www.googleapis.com/auth/gmail.readonly https://www.googleapis.com/auth/gmail.send'
* }
* @return {Promise}
* @private
*/
_initClient (params) {
return new Promise(function (resolve, reject) {
// Client Init
const initClient = function () {
window.gapi.client.init(params).then(() => {
resolve()
}, (error) => {
console.error('gapi.client.init - Error', error)
alert(`gapi.client.init - Error: ${error.error}\n Details: ${error.details}`)
})
}
window.gapi.load('client:auth2', initClient)
})
}
...
Получение сообщений (Users.messages: list)
Получить список сообщений пользователя. Более подробную информацию по этой команде можно посмотреть здесь
Прежде чем выполнить команду необходимо авторизироваться пользователю на Google сервере. Для этого нужно выполнить функцию авторизации, см. пр.2:
пр.2
...
/**
* Google SignIn
* @param successCallback (Function)
* @param errorCallback (Function)
*/
signIn (successCallback, errorCallback) {
window.gapi.auth2.getAuthInstance().signIn().then(function (googleUser) {
successCallback(googleUser)
if (debug) {
console.log('GoogleAuth.signIn - OK')
}
}, function (error) {
errorCallback(error)
console.log('GoogleAuth.signIn - Error: ', error)
})
}
...
После авторизации пользователя можно выполнить команду, см. пр.3:
пр.3
...
/**
* Retrieve Messages in user's mailbox matching query.
*
* @param {String} userId User's email address. The special value 'me'
* can be used to indicate the authenticated user.
* @param {String} query String used to filter the Messages listed.
* @param {Function} callback Function to call when the request is complete.
*/
function listMessages(userId, query, callback) {
var getPageOfMessages = function(request, result) {
request.execute(function(resp) {
result = result.concat(resp.messages);
var nextPageToken = resp.nextPageToken;
if (nextPageToken) {
request = gapi.client.gmail.users.messages.list({
'userId': userId,
'pageToken': nextPageToken,
'q': query
});
getPageOfMessages(request, result);
} else {
callback(result);
}
});
};
var initialRequest = gapi.client.gmail.users.messages.list({
'userId': userId,
'q': query
});
getPageOfMessages(initialRequest, []);
}
...
Получение специфического сообщения (Users.messages: get)
Получить специфическое сообщение пользователя. Более подробную информацию по этой команде можно посмотреть здесь
Прежде чем выполнить команду необходимо авторизироваться пользователю на Google сервере. Для этого нужно выполнить функцию авторизации, см. пр.2:
После авторизации пользователя можно выполнить команду, см. пр.4:
пр.4
...
/**
* Get Message with given ID.
*
* @param {String} userId User's email address. The special value 'me'
* can be used to indicate the authenticated user.
* @param {String} messageId ID of Message to get.
* @param {Function} callback Function to call when the request is complete.
*/
function getMessage(userId, messageId, callback) {
var request = gapi.client.gmail.users.messages.get({
'userId': userId,
'id': messageId
});
request.execute(callback);
}
...
Получение сообщений в формате (text/html; charset="UTF-8")
Для получения сообщений в формате (text/html; charset="UTF-8") используются команды (Users.messages: list/get).
Прежде чем выполнить эти команды необходимо авторизироваться пользователю на Google сервере см. пр.2. После авторизации пользователя можно выполнить следующий код, см. пр.5:
пр.5
...
/**
* Get inbox messages
* @param params
* etc. {
userId: 'me',
labelIds: 'INBOX',
maxResults: 10
* }
* @return {Promise}
*/
getInbox (params) {
let arrPromises = []
return new Promise((resolve, reject) => {
_getMyMessagesList(params)
.then(list => {
_.forEach(list, function (item) {
arrPromises.push(_getMessageForId(item.id, params.userId))
})
const allPromises = Promise.all(arrPromises)
resolve(allPromises)
})
})
}
_getMyMessagesList (params) {
// Execute this request for 'gmail.users.messages.list'
const request = window.gapi.client.gmail.users.messages.list(params)
return new Promise((resolve, reject) => {
request.execute(function (response) {
if (debug) {
console.log('api.gmail.users.messages.list - Executed: ', response.messages)
}
resolve(response.messages)
})
})
}
_getMessageForId (id, userId) {
let _message = {}
// Execute this request for 'gmail.users.messages.get'
const messageRequest = window.gapi.client.gmail.users.messages.get({
'userId': userId,
'id': id
})
return new Promise((resolve, reject) => {
messageRequest.execute(message => {
// Parsing message
_message.id = message.id
_message.from = _getHeader(message.payload.headers, 'From')
_message.subject = _getHeader(message.payload.headers, 'Subject')
_message.date = _getHeader(message.payload.headers, 'Date')
_message.reply_to = _getHeader(message.payload.headers, 'Reply-to')
_message.message_id = _getHeader(message.payload.headers, 'Message-ID')
_message.body = _getBody(message.payload)
if (debug) {
console.log('api.gmail.users.messages.get - Executed: ', _message)
}
resolve(_message)
})
})
}
_getHeader (headers, index) {
let headerValue = ''
_.forEach(headers, function (header) {
if (header.name.toLowerCase() === index.toLowerCase()) {
headerValue = header.value
}
})
return headerValue
}
_getBody (message) {
var encodedBody = ''
try {
if (typeof message.parts === 'undefined') {
encodedBody = message.body.data
} else {
encodedBody = _getHTMLPart(message.parts)
}
return _b64UrlDecodeUnicode(encodedBody)
} catch (error) {
console.error('apiGmail._getBody - Error', error)
throw error
}
}
_getHTMLPart (arr) {
for (let x = 0; x <= arr.length; x++) {
if (typeof arr[x].parts === 'undefined') {
if (arr[x].mimeType === 'text/html') {
return arr[x].body.data
}
} else {
return _getHTMLPart(arr[x].parts)
}
}
return ''
}
/**
* To decode the Base64-encoded-url value back into a String
*
* @param str
* @return {string}
*/
_b64UrlDecodeUnicode (str) {
const encodedBody = str.replace(/-/g, '+').replace(/_/g, '/').replace(/\s/g, '')
// Going backwards: from bytestream, to percent-encoding, to original string.
return decodeURIComponent(atob(encodedBody).split('').map(function (c) {
return '%' + ('00' + c.charCodeAt(0).toString(16)).slice(-2)
}).join(''))
}
...