使用 nodejs 中的服务帐户域范围委托通过 Google Apps Gmail 发送邮件
Send mail via Google Apps Gmail using service account domain wide delegation in nodejs
我已经阅读教程和查看示例 2 天了,但没有成功。
我想在 NodeJS 环境中使用 Google Apps Gmail 帐户发送电子邮件,但是,我收到 Google API:
的 400
回复
{[Error: Bad Request]
code: 400,
errors:
[{
domain: 'global',
reason: 'failedPrecondition',
message: 'Bad Request'
}]
}
这是我到目前为止所做的:
- 在 Google 云平台
中创建了一个项目
- 创建了一个服务帐户
- 为服务帐户启用
Domain Wide Delegation
- 已下载
JSON
格式的服务帐户密钥
API Manager
> Credentials
我创建了 OAuth 2.0 client ID
- 为项目启用 Gmail API
在 Google Apps 管理控制台中:
- 在
Security
> Advanced Settings
> Manage API client access
中,我添加了上面步骤 4
中的 Client ID
- 我已经为
Client ID
添加了所有可能的范围
这是尝试发送电子邮件的代码:
const google = require('googleapis');
const googleKey = require('./google-services.json');
const jwtClient = new google.auth.JWT(googleKey.client_email, null, googleKey.private_key, ['https://www.googleapis.com/auth/gmail.send'], null);
jwtClient.authorize((err, tokens) => {
if (err) {
console.err(err);
return;
}
console.log('Google auth success')
var gmail = google.gmail({version: 'v1', auth: jwtClient})
var raw = <build base64 string according to RFC 2822 specification>
var sendMessage = gmail.users.messages.send({
auth: jwtClient,
userId: 'user@domain.com',
message: {
raw: raw
}
}, (err, res) => {
if (err) {
console.error(err);
} else {
console.log(res);
}
});
我可以看到 Google auth success
消息并且请求是使用正确初始化的令牌发送的:
headers:
{ Authorization: 'Bearer ya29.CjLjAtVjGNJ8fcBnMSS8AEXAvIm4TbyNTc6g_S99HTxRVmzKpWrAv9ioTI4BsLKXW7uojQ',
'User-Agent': 'google-api-nodejs-client/0.9.8',
host: 'www.googleapis.com',
accept: 'application/json',
'content-type': 'application/json',
'content-length': 2 }
但是,响应仍然是 400
所以我离解决方案只有一步之遥,问题是在创建 const jwtClient = new google.auth.JWT(googleKey.client_email, null, googleKey.private_key, ['https://www.googleapis.com/auth/gmail.send'], null);
时我没有提到要模拟的帐户。
正确的初始化应该是:
const jwtClient = new google.auth.JWT(googleKey.client_email, null, googleKey.private_key, ['https://www.googleapis.com/auth/gmail.send'], 'user@domain.com');
总而言之,正确的步骤是:
- 在Google云平台
中创建了一个项目
- 创建了一个服务帐户
- 为服务帐户启用
Domain Wide Delegation
- 已下载 JSON 格式的服务帐户密钥
API Manager
> Credentials
我创建了 OAuth 2.0 Client ID
- 为项目启用 Gmail API
在 Google Apps 管理控制台中:
- 在
Security
> Advanced Settings
> Manage API client access
中,我添加了上面第 4 步中的 Client ID
- 我已经为
Client ID
添加了所有可能的范围
这是发送邮件的代码:
const google = require('googleapis');
const googleKey = require('./google-services.json');
const jwtClient = new google.auth.JWT(googleKey.client_email, null, googleKey.private_key, ['https://www.googleapis.com/auth/gmail.send'], '<user to impersonate>');
jwtClient.authorize((err, tokens) => {
if (err) {
console.err(err);
return;
}
console.log('Google auth success')
var gmail = google.gmail({version: 'v1'})
var raw = <build base64 string according to RFC 2822 specification>
var sendMessage = gmail.users.messages.send({
auth: jwtClient,
userId: '<user to impersonate>',
resource: {
raw: raw
}
}, (err, res) => {
if (err) {
console.error(err);
} else {
console.log(res);
}
});
希望对其他人有所帮助
非常感谢@agoldis。总结步骤和代码都非常有帮助。
它帮助我了解了一些我需要在通信路径的 GoogleWorkspace 和 ApplicationCode 端修复的问题。下面是我的 c# 实现,供任何需要它的人使用。
private static void Try4()
{
try {
//file included in project with properties: CopyToOutputDirectory = CopyAlways
var credential = GoogleCredential.FromFile("MyPrj-MyServiceAccount-Credentials.json")
.CreateScoped(new[] { GmailService.Scope.GmailSend })
.CreateWithUser("WhoIAmImpersonating@bla.com")
.UnderlyingCredential as ServiceAccountCredential;
var service = new GmailService(new BaseClientService.Initializer() { HttpClientInitializer = credential });
var nl = Environment.NewLine;
string plainText = "From: WhoIAmImpersonating@bla.com"
+ nl + "To: myfriend@gmail.com,"
+ nl + "Subject: This is the Subject"
+ nl + "Content-Type: text/html; charset=us-ascii"
+ nl
+ nl + "This is the message text.";
var newMsg = new Message() { Raw = Base64UrlEncode(plainText) };
service.Users.Messages.Send(newMsg, "WhoIAmImpersonating@bla.com").Execute();
Console.WriteLine("Message Sent OK");
}
catch (Exception ex) {
Console.WriteLine("Message failed");
}
}
private static string Base64UrlEncode(string input)
{
var inputBytes = System.Text.Encoding.UTF8.GetBytes(input);
return Convert.ToBase64String(inputBytes)
.Replace('+', '-')
.Replace('/', '_')
.Replace("=", "" );
}
我已经阅读教程和查看示例 2 天了,但没有成功。 我想在 NodeJS 环境中使用 Google Apps Gmail 帐户发送电子邮件,但是,我收到 Google API:
的400
回复
{[Error: Bad Request]
code: 400,
errors:
[{
domain: 'global',
reason: 'failedPrecondition',
message: 'Bad Request'
}]
}
这是我到目前为止所做的:
- 在 Google 云平台 中创建了一个项目
- 创建了一个服务帐户
- 为服务帐户启用
Domain Wide Delegation
- 已下载
JSON
格式的服务帐户密钥 API Manager
>Credentials
我创建了OAuth 2.0 client ID
- 为项目启用 Gmail API
在 Google Apps 管理控制台中:
- 在
Security
>Advanced Settings
>Manage API client access
中,我添加了上面步骤4
中的Client ID
- 我已经为
Client ID
添加了所有可能的范围
这是尝试发送电子邮件的代码:
const google = require('googleapis');
const googleKey = require('./google-services.json');
const jwtClient = new google.auth.JWT(googleKey.client_email, null, googleKey.private_key, ['https://www.googleapis.com/auth/gmail.send'], null);
jwtClient.authorize((err, tokens) => {
if (err) {
console.err(err);
return;
}
console.log('Google auth success')
var gmail = google.gmail({version: 'v1', auth: jwtClient})
var raw = <build base64 string according to RFC 2822 specification>
var sendMessage = gmail.users.messages.send({
auth: jwtClient,
userId: 'user@domain.com',
message: {
raw: raw
}
}, (err, res) => {
if (err) {
console.error(err);
} else {
console.log(res);
}
});
我可以看到 Google auth success
消息并且请求是使用正确初始化的令牌发送的:
headers:
{ Authorization: 'Bearer ya29.CjLjAtVjGNJ8fcBnMSS8AEXAvIm4TbyNTc6g_S99HTxRVmzKpWrAv9ioTI4BsLKXW7uojQ',
'User-Agent': 'google-api-nodejs-client/0.9.8',
host: 'www.googleapis.com',
accept: 'application/json',
'content-type': 'application/json',
'content-length': 2 }
但是,响应仍然是 400
所以我离解决方案只有一步之遥,问题是在创建 const jwtClient = new google.auth.JWT(googleKey.client_email, null, googleKey.private_key, ['https://www.googleapis.com/auth/gmail.send'], null);
时我没有提到要模拟的帐户。
正确的初始化应该是:
const jwtClient = new google.auth.JWT(googleKey.client_email, null, googleKey.private_key, ['https://www.googleapis.com/auth/gmail.send'], 'user@domain.com');
总而言之,正确的步骤是:
- 在Google云平台 中创建了一个项目
- 创建了一个服务帐户
- 为服务帐户启用
Domain Wide Delegation
- 已下载 JSON 格式的服务帐户密钥
API Manager
>Credentials
我创建了OAuth 2.0 Client ID
- 为项目启用 Gmail API
在 Google Apps 管理控制台中:
- 在
Security
>Advanced Settings
>Manage API client access
中,我添加了上面第 4 步中的Client ID
- 我已经为
Client ID
添加了所有可能的范围
这是发送邮件的代码:
const google = require('googleapis');
const googleKey = require('./google-services.json');
const jwtClient = new google.auth.JWT(googleKey.client_email, null, googleKey.private_key, ['https://www.googleapis.com/auth/gmail.send'], '<user to impersonate>');
jwtClient.authorize((err, tokens) => {
if (err) {
console.err(err);
return;
}
console.log('Google auth success')
var gmail = google.gmail({version: 'v1'})
var raw = <build base64 string according to RFC 2822 specification>
var sendMessage = gmail.users.messages.send({
auth: jwtClient,
userId: '<user to impersonate>',
resource: {
raw: raw
}
}, (err, res) => {
if (err) {
console.error(err);
} else {
console.log(res);
}
});
希望对其他人有所帮助
非常感谢@agoldis。总结步骤和代码都非常有帮助。
它帮助我了解了一些我需要在通信路径的 GoogleWorkspace 和 ApplicationCode 端修复的问题。下面是我的 c# 实现,供任何需要它的人使用。
private static void Try4()
{
try {
//file included in project with properties: CopyToOutputDirectory = CopyAlways
var credential = GoogleCredential.FromFile("MyPrj-MyServiceAccount-Credentials.json")
.CreateScoped(new[] { GmailService.Scope.GmailSend })
.CreateWithUser("WhoIAmImpersonating@bla.com")
.UnderlyingCredential as ServiceAccountCredential;
var service = new GmailService(new BaseClientService.Initializer() { HttpClientInitializer = credential });
var nl = Environment.NewLine;
string plainText = "From: WhoIAmImpersonating@bla.com"
+ nl + "To: myfriend@gmail.com,"
+ nl + "Subject: This is the Subject"
+ nl + "Content-Type: text/html; charset=us-ascii"
+ nl
+ nl + "This is the message text.";
var newMsg = new Message() { Raw = Base64UrlEncode(plainText) };
service.Users.Messages.Send(newMsg, "WhoIAmImpersonating@bla.com").Execute();
Console.WriteLine("Message Sent OK");
}
catch (Exception ex) {
Console.WriteLine("Message failed");
}
}
private static string Base64UrlEncode(string input)
{
var inputBytes = System.Text.Encoding.UTF8.GetBytes(input);
return Convert.ToBase64String(inputBytes)
.Replace('+', '-')
.Replace('/', '_')
.Replace("=", "" );
}