Gmail API для отправки писем в Node.js

Заявление об ограничении ответственности:

  • Я следил за собственным руководством по быстрому запуску по Node.js от Google и успешно подключаюсь и использую gmail.users.labels.list() функциональность.
  • Я проверил здесь вопросы / ответы, например этот (он не использует API Node.js, о котором я спрашиваю ) или этот (аналогично этот), очевидно, это та же проблема, что и у меня, но решение не работает.

Моя проблема:

При использовании Google Node.js API я получаю сообщение об ошибке при отправке электронного письма. Ошибка:

{
    "code": 403,
    "errors": [{
        "domain": "global",
        "reason": "insufficientPermissions",
        "message": "Insufficient Permission"
    }]
}

Моя установка:

fs.readFile(secretlocation, function processClientSecrets(err, content) {
    if (err) {
        console.log('Error loading client secret file: ' + err);
        return;
    }
    authorize(JSON.parse(content), sendMessage);
});

function sendMessage(auth) {
    var raw = makeBody('[email protected]', '[email protected]', 'subject', 'message test');
    gmail.users.messages.send({
        auth: auth,
        userId: 'me',
        message: {
            raw: raw
        }
    }, function(err, response) {
        res.send(err || response)
    });
}

Функция processClientSecrets взята из упомянутого выше руководства Google. Он читает мой .json файл, в котором есть мои access_token и refresh_token. makeBody функция предназначена для создания закодированного основного сообщения.

В переменных конфигурации у меня также есть:

var SCOPES = [
    'https://mail.google.com/',
    'https://www.googleapis.com/auth/gmail.modify',
    'https://www.googleapis.com/auth/gmail.compose',
    'https://www.googleapis.com/auth/gmail.send'
];

Почему должно работать:

  • процесс авторизации работает для метода gmail.users.labels.list().
  • тело сообщения, которое я тестирую, работает, если я проверяю его на тесте Google страница.

Мой вопрос:

Моя установка неправильная? Были ли изменения в API? Что мне не хватает?


person Sergio    schedule 31.12.2015    source источник
comment
Убедитесь, что у вас авторизованы необходимые области: developers.google .com / gmail / api / v1 / reference / users / messages /.   -  person AboulEinein    schedule 31.12.2015
comment
@AboulEinein Я работаю, но все еще не работает, спасибо, что указали. Мне также пришлось иметь это при тестировании в Инструмент Google. В настоящее время у меня есть эти области проверки подлинности: https://mail.google.com/, gmail.compose, gmail.modify, gmail.send   -  person Sergio    schedule 31.12.2015
comment
Перейдите на Oauth Playground, авторизуйтесь в областях Gmail, возьмите access token и refresh token и поместите их в вашем .json-файле. Вы все еще получаете сообщение об ошибке?   -  person Tholle    schedule 01.01.2016
comment
@Tholle, спасибо, что посмотрели. Сделал тот шаг, который вы предложили, и теперь ошибка другая: {"code":400,"errors":[{"domain":"global","reason":"invalidArgument","message":"'raw' RFC822 payload message string or uploading message via /upload/* URL required"}]}   -  person Sergio    schedule 01.01.2016
comment
@Sergio Хм, это раздражает. Вы пытались сделать URL-адрес с raw строкой безопасным (замените все + на - и все / на _)?   -  person Tholle    schedule 01.01.2016
comment
@Sergio Darn :( Тогда я не знаю. Надеюсь, кто-нибудь еще сможет вмешаться.   -  person Tholle    schedule 02.01.2016
comment
@Tholle нашел мою проблему (ы). Спасибо за проверку!   -  person Sergio    schedule 02.01.2016
comment
@Sergio Отлично! Без проблем. :)   -  person Tholle    schedule 02.01.2016


Ответы (2)


Итак, я нашел проблему (ы).

Проблема №1. Следуя руководству по быстрому запуску по Node.js, пример в этом учебник имеет

var SCOPES = ['https://www.googleapis.com/auth/gmail.readonly'];

И когда я получил .json, который выглядит так:

{
    "access_token": "xxx_a_long_secret_string_i_hided_xxx",
    "token_type": "Bearer",
    "refresh_token": "xxx_a_token_i_hided_xxx",
    "expiry_date": 1451721044161
}

эти токены были созданы с учетом только области auth/gmail.readonly в коде руководства.

Поэтому я удалил первый .json, добавил области из моего окончательного массива областей (я написал в вопросе) и снова запустил настройку учебника, получив новый токен.

Проблема №2

В объекте, переданном в API, который я отправлял:

{
    auth: auth,
    userId: 'me',
    message: {
        raw: raw
    }
}

но это неправильно, message ключ должен называться resource.


Окончательная настройка:

Вот что я добавил в код учебника:

function makeBody(to, from, subject, message) {
    var str = ["Content-Type: text/plain; charset=\"UTF-8\"\n",
        "MIME-Version: 1.0\n",
        "Content-Transfer-Encoding: 7bit\n",
        "to: ", to, "\n",
        "from: ", from, "\n",
        "subject: ", subject, "\n\n",
        message
    ].join('');

    var encodedMail = new Buffer(str).toString("base64").replace(/\+/g, '-').replace(/\//g, '_');
        return encodedMail;
}

function sendMessage(auth) {
    var raw = makeBody('[email protected]', '[email protected]', 'test subject', 'test message');
    gmail.users.messages.send({
        auth: auth,
        userId: 'me',
        resource: {
            raw: raw
        }
    }, function(err, response) {
        res.send(err || response)
    });
}

И называть все с помощью:

fs.readFile(secretlocation, function processClientSecrets(err, content) {
    if (err) {
        console.log('Error loading client secret file: ' + err);
        return;
    }
    // Authorize a client with the loaded credentials, then call the
    // Gmail API.
    authorize(JSON.parse(content), sendMessage);
});
person Sergio    schedule 02.01.2016
comment
как прикрепить полезную нагрузку html? - person Arjun Kava; 30.01.2017
comment
@ArjunKava просто установил Content-Type: text/html; вместо Content-Type: text/plain;. - person Jyotman Singh; 03.05.2017
comment
спасибо @JyotmanSingh, но мне также нужно отправлять вложения в полезной нагрузке, которые являются моими локальными файлами ПК, я пробовал использовать тип содержимого mime, но все еще не работает. - person Arjun Kava; 05.05.2017
comment
Пожалуйста, не могли бы вы объяснить, почему вам нужно сделать некоторые замены необработанного сообщения base64. Спасибо - person IcanDivideBy0; 08.05.2017
comment
Я также хотел бы знать, почему они заменяют контент base64. Кроме того, где вы нашли документацию о необработанном контенте, внутри атрибута ресурса. - person grabbag; 21.02.2018
comment
этот код дал мне эту ошибку: 'raw' RFC822 payload message string or uploading message via /upload/* URL required [400].. Это можно исправить, обновив google-auth-api до последней версии. github.com/google/google-api-nodejs-client/issues/ 979 - person Arvind Sridharan; 16.03.2018
comment
Вы забыли const gmail = google.gmail({version: 'v1', auth}); в sendMessage(). Также res в sendMessage() не определялся. Прокомментировав это, я получил такую ​​ошибку: Error: Insufficient Permission. Кто-нибудь еще с этим вопросом? - person Soubriquet; 25.04.2019
comment
привет, как я могу получить список адресов электронной почты для входящих? пожалуйста посоветуй. Я уже получил ярлыки списков - person Vishnu Chauhan; 31.03.2020

Итак, для тех, кто смотрит на это, пытается получить тестовое электронное письмо, отправленное из их API, но не может выполнить эту работу, вот что вам нужно сделать:

Шаг 1. Замените

var SCOPES = ['https://www.googleapis.com/auth/gmail.readonly'];

с этим:

var SCOPES = [
    'https://mail.google.com/',
    'https://www.googleapis.com/auth/gmail.modify',
    'https://www.googleapis.com/auth/gmail.compose',
    'https://www.googleapis.com/auth/gmail.send'
];

Шаг 2. В конце примера кода Google добавьте следующее:

function makeBody(to, from, subject, message) {
    var str = ["Content-Type: text/plain; charset=\"UTF-8\"\n",
        "MIME-Version: 1.0\n",
        "Content-Transfer-Encoding: 7bit\n",
        "to: ", to, "\n",
        "from: ", from, "\n",
        "subject: ", subject, "\n\n",
        message
    ].join('');

    var encodedMail = new Buffer(str).toString("base64").replace(/\+/g, '-').replace(/\//g, '_');
        return encodedMail;
}

function sendMessage(auth) {
    var raw = makeBody('[email protected]', '[email protected]', 'This is your subject', 'I got this working finally!!!');
    const gmail = google.gmail({version: 'v1', auth});
    gmail.users.messages.send({
        auth: auth,
        userId: 'me',
        resource: {
            raw: raw
        }
    
    }, function(err, response) {
        return(err || response)
    });
}

fs.readFile('credentials.json', function processClientSecrets(err, content) {
    if (err) {
        console.log('Error loading client secret file: ' + err);
        return;
    }
    // Authorize a client with the loaded credentials, then call the
    // Gmail API.
    authorize(JSON.parse(content), sendMessage);
});

Шаг 3 (необязательно)

Удалите эту строку:

authorize(JSON.parse(content), listLabels);

И эти:

/**
 * Lists the labels in the user's account.
 *
 * @param {google.auth.OAuth2} auth An authorized OAuth2 client.
 */
 function listLabels(auth) {
   const gmail = google.gmail({version: 'v1', auth});
   gmail.users.labels.list({
     userId: 'me',
   }, (err, res) => {
     if (err) return console.log('The API returned an error: ' + err);
     const labels = res.data.labels;
     if (labels.length) {
       console.log('Labels:');
       labels.forEach((label) => {
         console.log(`- ${label.name}`);
       });
     } else {
       console.log('No labels found.');
     }
   });
 }

(Чтобы на консоли не появлялись случайные метки)

person Vincent Morris    schedule 18.07.2019