mailgun incoming mail event fetch attachment url - node.js

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.

Related

Unable to send a file via an HTTP POST request because the file extension is incorrect for a Buffer retrieved from AWS S3

I am in a Node.JS application. (Node version 14 if that matters)
Also I am using node-fetch (v2) to send my request.
I am trying to send a Send Fax Request to Documo. The documentation can be found here: https://docs.documo.com/#da8dc725-8327-470c-83e4-34b40205cfa2.
As part of the request I want to send a pdf file that I have stored in S3. I have the following code to accomplish that:
const s3Object = await s3Client.send(
new GetObjectCommand({
Bucket: bucket,
Key: key,
})
const formData = new FormData();
formData.append("faxNumber", faxNumber);
formData.append("coverPage", "true");
formData.append("recipientName", recipientName);
formData.append("senderName", senderName);
formData.append("subject", subject);
formData.append("notes", note);
formData.append("webhookId", webhookId);
formData.append("attachments", s3Object.Body);
// ERROR: File extension 'pdf%22&x-id=getobject' is not allowed. Allowed formats: doc,docx,fodt,gif,htm,html,jpeg,jpg,odp,ods,odt,pdf,png,ppt,pptx,rtf,tif,tiff,txt,xls,xlsx,csv
const response = await fetch(`${BASE_DOCUMO_URL}/v1/faxes`, {
method: "POST",
headers: {
Authorization: DEMO_API_KEY,
ContentType: "multipart/form-data",
},
body: formData,
});
I am getting the following error from Documo:
"File extension 'pdf%22&x-id=getobject' is not allowed. Allowed formats: doc,docx,fodt,gif,htm,html,jpeg,jpg,odp,ods,odt,pdf,png,ppt,pptx,rtf,tif,tiff,txt,xls,xlsx,csv"
From what I understand it looks like the GetObjectCommand from S3 is appending an x-id in the file stream which the Documo client is not happy with. Ideally I don't want to recreate this file in memory and I just want to take the result from S3 to send through my POST request. (Although I could be convinced to just do that if there is no better option or I don't need to worry about holding files in memory).
What are my options. I've tried playing around with ResponseContentDisposition in GetObjectCommand to no avail

Add attachments to Invoices in Xero using node js SDK or API

I am trying to add attachments to existing invoices in xero.
I am using xero-node sdk (https://github.com/XeroAPI/xero-node#readme) for this integration and they provide a method for adding attachment as follows:
this.xero.accountingApi.createInvoiceAttachmentByFileName(tenantId, invoiceid, filenameInvoice,includeOnline,readStream )
The issue here is it requires an fs.ReadStream object for readStream.
The file I am trying to upload is present in cloud and I cannot download it and store it in file system before sending to Xero. I want to send the file present in azure cloud directly to xero. I have the url of file so I can get the content as a variable by making http request but there is no option to send this content to Xero.
There is an API available for this as well (here https://developer.xero.com/documentation/api/attachments) apart from the sdk. But I am not sure how I can send the file that I have to this API in body as it expects RAW data. Are there any specific headers or encodings required to call this API with file content in body? Because this is also not working for me if I just pass the body of the response I got from azure file url, as body to this Xero Attachment API. It tries for a long time and gives timeout error.
yes you are correct. There are additional headers/manipulation you need to do to upload files.
Please checkout the sample app - we've got it queued up to show exactly how to upload files: https://github.com/XeroAPI/xero-node-oauth2-app/blob/master/src/app.ts#L1188
Something like the following should get you sorted:
import * as fs from "fs";
const path = require("path");
const mime = require("mime-types");
const totalInvoices = await xero.accountingApi.getInvoices('your-tenantId-uuid', undefined, undefined, undefined, undefined, undefined, undefined, ['PAID']);
// Attachments need to be uploaded to associated objects https://developer.xero.com/documentation/api/attachments
// CREATE ATTACHMENT
const filename = "xero-dev.png";
const pathToUpload = path.resolve(__dirname, "../path-to-your.png");
const readStream = fs.createReadStream(pathToUpload);
const contentType = mime.lookup(filename);
const fileAttached = await xero.accountingApi.createInvoiceAttachmentByFileName(req.session.activeTenant.tenantId, totalInvoices.body.invoices[0].invoiceID, filename, true, readStream, {
headers: {
"Content-Type": contentType,
},
});
I ended up adding the link to file in History and Notes section of the invoice. Even though this is not the best solution, It serves the purpose of showing invoices to the customer.
Thanks to #SerKnight for your answer.

Send multipart gmail email which is huge attachments

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.

getting 403 error while sending file to githib via REST using nodejs

I want to send multiple files to Github repository via nodejs. Tried several approaches and end up using node-rest-client module. Tried below code send a sample file to repository called 'metadata'. But after post I am getting error message "Request forbidden by administrative rules. Please make sure your request has a User-Agent header"...please let me know if anyone faced this error before and get rid of it.
convertval = "somedata";
var dataObj = {
"message": "my commit message",
"committer": {
"name": "Scott Chacon",
"email": "ravindra.devagiri#gmail.com"
},
"content": "bXkgbmV3IGZpbGUgY29udGVudHM="
}
debugger;
var Client = require('node-rest-client').Client;
var client = new Client()
var args = {
data: dataObj,
headers: { 'Content-Type': 'application/json' },
};
client.post("https://api.github.com/repos/metadata/contents", args, function (data, response) {
console.log("file send: True : " + data);
});
According to the REST API:
All API requests MUST include a valid User-Agent header. Requests with
no User-Agent header will be rejected.
First of all, you need to define 'User-Agent' with value 'request' in your request header. Refer to this link.
Second, endpoint you are trying to call might require authentication. Generate a personal token from here, add that token in your request header, 'Authorization': 'token '.
If you're using Git extensively in your code, I suggest you to use this - Nodegit.
Edit:
I don't think sending multiple files in a single request is possible in 'Contents' endpoints group (link).
You can checkout Git Data API (as discussed here).

How to pull attachments from Google Glass item?

I created NodeJS server that communicate with Google Glass, I want to know how to pull attachment from item, below you can see the item with attachments:
Note: in my project I already have:
*Send item item to glass(contact, card, location, etc..)
*Subscription to timeline collection
*Contact with callback to let Glass user share content - for more info Visit How to add another option to the share functionality of Google Glass?
Do I need to use the selfLink to pull the attachment? if yes then how I can execute HTTP request for the selfLink while including the token?
The selfLink refers to the URL of the timelineItem itself. You want to look at the attachments attribute of the object. It might look something like this:
{ "kind": "mirror#timelineItem",
"id": "da61598c-2890-4852-2123-031011dfa004",
...
"attachments": [
"id": ...
"contentType": "image/jpeg".
"contentUrl": "https://www.googleapis.com/mirror/v1/timeline/da61598c-2890-4852-2123-031011dfa004/attachments/ps:605507433604363824",
"isProcessingContent": false
]
}
You should check to make sure isProcessingContent is false before you try to fetch it, otherwise the fetch will fail. This is usually pretty quick for images, but can take longer for video.
See more at https://developers.google.com/glass/v1/reference/timeline/attachments
To fetch it, you can issue an HTTPS request to that URL with an Authorization header with a value of Bearer auth_token (replacing auth_token with the actual value of the auth token).
To make the request itself, you'll probably want to use the http.request() method. So something like this (untested) might work:
var item = {the item you got sent above};
var attachment = item.attachments[0];
if( !attachment.isProcessingContent ){
var contentUrl = url.parse( attachment.contentUrl );
var options = {
"hostname": contentUrl.hostname,
"path": contentUrl.path,
"headers": {
"Authorization": 'Bearer '+authToken;
}
}
https.request( options, function(res){
// Get the image from the res object
});
}
See the documentation for URL.parse and HTTPS.request for details.

Resources