I am trying to send an email which has attachments in it, using Gmail APIs, I am using NodeJS, I have read this document
https://developers.google.com/gmail/api/guides/uploads#multipart
But I am not sure what I am missing in headers, the following is the code
I have to send an email which has an attachment which is more than 25 MB so for that, I am using multipart of Gmail, following is the code
const options = {
uri: 'https://www.googleapis.com/upload/gmail/v1/users/xyz#gmail.com/messages/send?uploadType=multipart',
method: apiConfig.method,
media: {mimeType: 'message/rfc822', body: requestParameter.dataObj.raw},
headers: {
Authorization: 'Bearer ' + token,
'Content-type': 'message/rfc822'
},
json: true
}
According to the Send attachments with your Gmail documentation:
You can send up to 25 MB in attachments. If you have more than one attachment, they can't add up to more than 25 MB.
If your file is greater than 25 MB, Gmail automatically adds a Google Drive link in the email instead of including it as an attachment.
But the last sentence refers to the Gmail UI, and not if you are using the API.
So essentially you cannot upload directly the attachment to the Gmail - you will have to upload it to Google Drive first and afterwards send it in the e-mail.
A possible solution:
Upload the file which you want to send to Google Drive by using the Google Drive API v3. Since you want to upload a file bigger than 25 mb you should use the resumable upload. The resumable upload is a more reliable type of transfer and especially important with large files.
var options = {
url: 'https://www.googleapis.com/upload/drive/v3/files?uploadType=resumable',
headers: {
'Authorization': 'Bearer ' + token,
'Content-Type': 'application/json',
},
//other options
}
Retrieve the file from Drive by using the Drive API and set the permissions necessary to be able to share the file. Afterwards you have to use the NPM module async to synchronize the changes in the permissions.
var fileId = 'ID_OF_THE_FILE';
var permissions = [
{
'type': 'user',
'role': 'writer',
'emailAddress': 'user#example.com'
}, {
'type': 'domain',
'role': 'writer',
'domain': 'example.com'
}
];
Send the e-mail with the link for the file wanted in the body.
Note: you also have to authorize the necessary scopes both for Drive and Gmail.
Moreover, I suggest you check the following links since they might be of help:
NodeJS Quickstart Drive API;
Upload files to Drive;
Drive Permissions;
OAuth 2.0 Scopes for Google APIs.
Related
I call Gmail API using a nodejs script using the request library (not the google one).
When I write the attachment response into a pdf file, I can see that the content is incomplete (missing images, missing styles, etc...).
Code:
const attachment: IGoogleMailUserMessageAttachmentResource = await this.call(
'GET',
`/${message.id}/attachments/${part.body.attachmentId}`,
);
writeFileSync('/tmp/test.pdf', attachment.content, { flag: 'w+' });
Received file :
instead of :
Any idea ?
Thanks
Using python 3.6, requests==2.22.0
I am using the Google API to create an event: documentation
In the documentation I see:
attachments[].fileUrl string URL link to the attachment.
For adding Google Drive file attachments use the same format as in alternateLink property of the Files resource in the Drive API.
Required when adding an attachment.
writable
Can I insert a file attachment not via a link-url?
Will that require a separate call?
data = {
'summary': 'CALENDAR TESTING',
'location': 'Some fake location',
'description': 'This is a test',
'start': {
'dateTime': 'some iso datetime',
'timeZone': 'some tz',
},
'end': {
'dateTime': 'some iso datetime',
'timeZone': 'some tz',
},
}
url = 'https://www.googleapis.com/calendar/v3/calendars/{}/events'.format(calendar_id)
headers = {
'Authorization': 'Bearer {}'.format(access_token),
'Accept': 'application/json',
'Content-Type': 'application/json',
}
response = requests.post(
url,
data=json.dumps(data),
headers=headers,
)
Example of an attachment-generating-payload sent to an already existing event in Office365:
data = {
"#odata.type": "#microsoft.graph.fileAttachment",
"name": "<String, file name>.pdf",
"contentBytes": <b64 encoded pdf bytes>
}
My goal is to attach a PDF file to the event.
In case I missed a documentation reference please point me to it - otherwise I will appreciate what is necessary to add to the above Google event creation payload to make this happen, or the url + payload schema to attach post-event creation.
Thank you!
Seems like Google does not support events attachments that are not store on Drive.
I am evaluating possible workarounds for the issue.
I have a problem with the file upload on google drive using the package googleapis (v.40):
In my web application (written in Vue js) i need to upload an image file of user 'A' into the google drive space of user 'B' using googleapis.
For this, i have created a "service-account" from the google console platform (of user B) and generated the credentials.json for the API access. (JWToken,service-to-service scenario)
In my web application, after getting the AccessToken by means the json credentials of the service account, i'm ready to upload the file. But, when i call the drive.files.create(...) api i get the following error:
Invalid multipart request with 0 mime parts.
Here some code:
...
// get google api
const {google} = require("googleapis");
const drive = google.drive("v3");
// get authorization token
let authToken = await getAuthToken() // it perfectly works
console.log(authToken)
let metadata = {
name: name,
parents: [idOfTheParentFolder]
}
let media = {
mimeType: 'image/jpeg',
body: file
}
let objImage = {
auth: authToken,
resource:metadata,
media: media,
fields: 'id',
}
drive.files.create(objImage, function (error, success) {
if (!error) {
...
}
else{
// here i got the error in question
}
})
I've tried exactly this code in a single node js file and it works fine, but it doesn't works in the web browser Vue application.
Let me say first that the API for showing the files (drive.files.list()) and the API for create a folder (drive.files.create()) they work just fine in my web application.
Any suggestion?
I have a Chrome Packaged App that uses oauth2 to authenticate to YouTube. I'm using YouTube to determine the user's channel (via the channel endpoint).
It works for the first user authenticated. But if I switch to a different user, the same YouTube call returns the previous user's data (i.e. channel).
Here are the steps I'm going through.
I get my auth token via a call to getAuthToken:
chrome.identity.getAuthToken({ interactive: true, scopes: ['https://www.googleapis.com/auth/youtube'] })
I get their channel information. I make a call to the channels endpoint like so:
const url = 'https://www.googleapis.com/youtube/v3/channels?part=snippet&mine=true';
const headers = { Authorization: `Bearer ${token}` };
const config = {
url,
method: 'get',
headers,
responseType: 'json',
};
return axios(config);
This works! The result of the call gives me the channel information.
The user removes their account. I use the same sequence of calls that the Google Demo uses (like this example):
a. call chrome.identiy.removeCachedAuthToken({ token }) with the token
b. call https://accounts.google.com/o/oauth2/revoke?token=${token} to revoke it
Everything is cleared out, I think.
If I look at chrome://identity-internals/ I still see the token, but the Token Status is set to Not Found
The issue:
I repeat from step 1, but I chose a different user.
I confirm that I get a new token that is different than the one I had previously
The call to the YouTube channels api returns the previous user's channel.
It turns out it was a caching issue with youtube.
I had to add 'Cache-Control': 'no-cache' to my headers.
Here is the full headers line:
const headers = {
Authorization: `Bearer ${token}`,
'Cache-Control': 'no-cache',
};
I have a node endpoint that receives an incoming email in json, complete with any attachments from mailgun.
The attachments are in a json array (xxx.com is used for privacy)
attachments: '[{"url": "https://sw.api.mailgun.net/v3/domains/xxx.com/messages/eyJwIjpmYWxzZSwiayI6ImZhMTU0NDkwLWVmYzgtNDVlNi1hYWMyLTM4M2EwNDY1MjJlNCIsInMiOiI2NmU1NmMzNTIwIiwiYyI6InRhbmtiIn0=/attachments/0", "content-type": "image/png", "name": "ashfordchroming_logo.png", "size": 15667}]
But if i type the url in the browser:
https://sw.api.mailgun.net/v3/domains/xxx.com/messages/eyJwIjpmYWxzZSwiayI6ImZhMTU0NDkwLWVmYzgtNDVlNi1hYWMyLTM4M2EwNDY1MjJlNCIsInMiOiI2NmU1NmMzNTIwIiwiYyI6InRhbmtiIn0=/attachments/0
I get
{
"message": "Domain not found: xxx.com"
}
I wanted the simplest way to show the image attachment in HTML, I was hoping the URL would just work since mailgun store the attachment.
So I was just trying to render the url in a template from Node.
Do I need to attach auth / API key credentials to the front of the URL to do this to test and make work?
If you want to access the raw json, go to
https://sw.api.mailgun.net/v3/domains/xxx.com/messages/eyJwIjpmYWxzZSwiayI6ImZhMTU0NDkwLWVmYzgtNDVlNi1hYWMyLTM4M2EwNDY1MjJlNCIsInMiOiI2NmU1NmMzNTIwIiwiYyI6InRhbmtiIn0=/attachments/0
using username 'api' and password 'your-mailgun-privatekey'.
To do this programmatically, use the request package to read the buffer.
const rp = require("request-promise");
let file = rp.get({
uri: "attachement-url",
headers: {
"Accept": "message/rfc2822"
}
}).auth("api", "your private key")
/**Access the buffer here**/
file.on('data', (s => {
console.log(s)
}))
file.pipe(fs.createWriteStream("./my-image.jpg"))
you can pipe the file to S3 or any cloud bucket.