Can't receive email with attachment from mailgun - node.js

I create router from mailgun to forward emails to my website endpoint www.example.com/messages
and I received emails successfully when it only text but when i attach file to this email, I don't receive any thing and the request body is empty
export const incomingEmails = async (req, res) => {
const from = req.body.from.split('<')[0].trim();
const sender = req.body.sender;
const recipient = req.body.recipient;
const subject = req.body.subject;
const html = req.body['stripped-html'];
try {
const incomingEmail = new Support({
from,
sender,
recipient,
subject,
html
})
await incomingEmail.save();
res.sendStatus(200)
} catch (error) {
res.status(500)
next(new Error('something went wrong'))
}}
i'm using url encoded middle ware
app.use(express.urlencoded())
note the stack I use is node and express at at backend

I ran into the same issue and I figured out why. I used the forward method to receive emails on my backend. The forward method only works when there is no attachment. With attachments, Mailgun will return an empty body because Mailgun has to first store the attachments, which is asynchronous.
In order to solve this issue, you have to use the store method instead of the forward method:
store(notification endpoint)
Stores the message temporarily (for up to 3 days) on Mailgun’s servers
so that you can retrieve it later. This is helpful for large
attachments that may cause time-outs or if you just want to retrieve
them later to reduce the frequency of hits on your server.
You have to edit your route in the Mailgun web app: go under "Receiving" in the menu and then edit your existing route.
Instead of entering:
forward("http://example.com/callback")
You enter:
store(notify="http://example.com/callback")

Related

Indicating a WhatsApp message is received, via the Twilio API, in NodeJS?

We are creating a service that will receive WhatsApp messages via the Twilio service. This works, but our issue is that we can't work out how to tell the sender that our server has 'read' the message. The messages always appear as being 'delivered' and never 'read', even after responding to the message. We have looked in the documentation, but can't seem to see how to do this.
Our server is written in NodeJS and is using Express for HTTP side.
Below is an equivalent of the code we are using (not a running example):
import { twiml } from 'twilio';
const { MessagingResponse } = twiml;
async receiveMessage(req: Request, res: Response, next: NextFunction) {
const message = req.body;
// Send back an empty response, we will process asynchronously
const immediateResponse = new MessagingResponse();
res.setHeader('content-type', 'text/xml');
res.send(immediateResponse.toString());
// TODO indicate message as read
// Do what ever logic is needed for given message
const replyMessage = await processMessage(message);
const messageToTwilio = {
body: replyMessage,
from: message.To,
to: message.From
};
const twilioResponse = await this.client.messages.create(messageToTwilio);
// Record value of twilioResponse in DB
}
Can anyone suggest what in the API I should be using for this?
I contacted Twilio on this issue and it turns out this is not currently possible. While they consider this a useful functionality, it is not currently a priority for implementation.
Note, It is possible to get the delivery status of outgoing messages, via the status webhook, but it is not possible to indicate to the remote party that the incoming message was 'read'.

Why the request is being save in express?

I have a problem.
I am developing an API with Node and the express framework to send transactional email using Mandril.
I download the powerdrill library to call the Mandrill API.
Everything is working fine, the emails are being sent ok, except for the problem that the request in the post is saving.
For example, if I call the API once I will send one email, and if I send a second one I will send 2 emails (the first one that I sent and the new one), and if I call the API once again I will send 3 email (the first 2 and the new one).
As you can see I sent 1 email using the request welcome. In the second one I called other request called submittedApplication but when I call the API using POSTMAN 2 emails were sent 1.-the new one and 2.- the first one again.
Does anyone know why the request is saving?
var express = require('express'),
router = express.Router(),
config = require('config'),
Message = require('powerdrill').Message;
var message = new Message();
router.get('/',function(req,res){
res.send('test ok Mandrillllll');
})
router.post('/welcomeGorn',function(req,res){
console.log(req.body);
message.apiKey(config.mandrillKey)
.subject(req.body.subject)
.template(req.body.template)
.from(config.mandrilEmail)
.to(req.body.to)
.tag('complex')
.globalMergeVar('VERIFY_EMAIL',req.body.linkVefifyEmail)
.send(function(err, resp) {
//console.log(resp);
res.send(resp).end();
});
});
router.post('/submittedApplication',function(req,res){
console.log(req.body);
message.apiKey(config.mandrillKey)
.subject(req.body.subject)
.template(req.body.template)
.from(config.mandrilEmail)
.to(req.body.to)
.tag('complex')
.globalMergeVar('RECRUITER_NAME',req.body.recruiterName)
.globalMergeVar('RECRUITER_EXTENSION',req.body.recruiterExtension)
.globalMergeVar('RECRUITER_EMAIL',req.body.recruiterEmail)
.send(function(err, resp) {
//console.log(resp);
res.send(resp);
});
});
module.exports = router;
The console is showing me this warning:
Powerdrill: Attempting to add the same email twice. Using data from first instance
You can find this warning here
I think the problem is message variable is saving all information and sending all together every time. Try to initialize it at the beginning of every method:
router.post('/welcomeGorn',function(req,res){
var message = new Message();

Very simple Node.js POST form inquiries

I have a simple node.js app using express static and nodemailer with a POST form that emails the filled fields to myself. My problems are very simple, I'm just quite new to Node so I can't find a way to do them.
My first problem is that I can't find a way to put all the form data into the email's text. Below, I am trying to store my form data in a JSON and call it in the email text, but it doesn't work. It has only correctly worked for me when I only used one variable (ex. just req.body.name) for the text. How can I format my data together in the email?
My second problem is that I can find a way to handle the app after the email is sent. I want it to redirect to a success page, as shown in the marked line, but it does not work. Instead, the page goes to /reqform and displays an error message saying success.html doesn't exist (it is in the same public folder as my html file). I believe the problem lies in my sendFile usage, but I'm not sure.
app.post('/reqform', urlencodedParser, function (req, res) {
response = {
name: req.body.name,
email: req.body.email,
phone: req.body.phone
};
var mailContent = {
from: 'myemail#gmail.com',
to: 'myemail#gmail.com',
subject: 'Service Request From req.body.name',
text: response //*** Problem #1
};
transporter.sendMail(mailClient, function (error, info) {
if (error) {
console.log(error);
} else {
res.sendFile("success.html"); //** Problem #2
}
});
})
Any help is greatly appreciated. Thanks!
The default string value for a JavaScript Object is just "[object Object]". If you want anything else, you'll have to be specific with how you want it represented.
For example, JSON is a text/string format that represents values like Objects. It's separate from the Object itself, so you'll need to convert to use it:
var mailContent = {
// ...
text: JSON.stringify(response)
}
Or, provide your own formatting:
var mailContent = {
// ...
text: `Name: ${response.name}\nEmail: ${response.email}\nPhone: ${response.phone}`
}
It might be better to use res.redirect() in this case, allowing the client/browser to request success.html via your application's static() middleware:
res.redirect('/success.html');
res.sendFile() doesn't collaborate with any static() middleware to know about your public folder. It expects you to provide a full path either directly or with its root option:
res.sendFile(path.join(__dirname, 'public/success.html'));

Nodejs deleting uploaded files after specific time

I am building a hosting server with Node and MongoDB. Process of working look something like this:
User open page with form which contains 4 inputs:
sender email
receiver email
message from sender to receiver
files (multiple)
User fills all inputs properly and sends POST request on server.
Server handles form with multer and saves files, then in callback the object with fields data where is stored info received from form is prepared and sent to database on MongoLab.
In callback of saving doc in database, server sends mails to sender and receiver with generated link from where they can download uploaded files.
Now I would like to implement additional input to form, where user can set date when his files should be deleted from the server.
So there are two things to do: delete files and delete doc in database on time set by the user.
Do you have some ideas how to implement such thing?
To delete a file, you can simply use fs.unlink()
const fs = require('fs');
const deleteFile = (file) => {
fs.unlink("path/to/file/folder/"+file, (err) => {
if (err) throw err;
}
}
You want to create a setTimeout(), but you need to find how much time is remaining before the date provided by the user, you should do something like this:
const time_remaining = (date_provided) => new Date(date_provided) - new Date();
Then just use setTimeout():
let timeOuts = []; // We create an array of timeouts in case we want to cancel one later
// I assume you use express and body-parser
app.post('/upload', (req, res) => {
const timer = setTimeout( () => deleteFile(req.body.file), time_remaining (req.body.date));
timeOuts.push(timer);
}

Access transcriptionText from twilio

I want to access the transcription text that has been generated by transcribe in my Twilio account under transcriptions as I want to compare user recorded response as text
twiml.say('Hi there! Please speak your response after the beep,-Get ready!')
.record({
transcribe:true,
timeout:5,
maxLength:30,
transcribeCallback:'/recording',
action:'/recording'
});
app.post('/recording', (request,response) => {
if(transcriptionText=='yes'){
twiml.say('thank you for positive response');
}
response.type('text/xml');
response.send(twiml.toString());
});
Twilio developer evangelist here.
When using transcription with <Record>, once the recording is complete the call will continue on to make a request to the action attribute synchronously. Whatever you return from the action attribute URL will control the call.
The actual transcription, however, takes a bit more time and when you get a webhook to the transcribeCallback URL it is done asynchronously, outside the context of the call. So, returning TwiML will not affect the call at all.
You will get the transcription text by inspecting the body of the request. There are plenty of parameters sent to the transcribeCallback, but the one you are looking for is the TranscriptionText. In your Node.js app, which looks like Express to me, you can get hold of it by calling request.body.TranscriptionText.
If you do want to affect the call when you receive the transcribe callback you will need to use the REST API to modify the call and redirect it to some new TwiML.
Let me know if that helps at all.
[edit]
From the comments I can see you are trying to drive a part of the call from a spoken response. The transcribeCallback URL isn't called immediately as the transcription needs to be done, so you need an action URL that you can send your caller to while you wait.
So, adjust your recording route to have different endpoints for action and transcribeCallback:
app.post("/voice", (request, response) => {
var twiml = new twilio.TwimlResponse();
twiml.say('Hi there! Please speak your response after the beep,-Get ready!')
.record({
transcribe:true,
timeout:5,
maxLength:30,
transcribeCallback:'/transcribe',
action:'/recording'
});
response.type('text/xml');
response.send(twiml.toString());
})
Then your recording endpoint will need to keep the user waiting while Twilio transcribes the text.
app.post('/recording', (request,response) => {
var twiml = new twilio.TwimlResponse();
// A message for the user
twiml.say('Please wait while we transcribe your answer.');
twiml.pause();
// Then redirect around again while we wait
twiml.redirect('/recording');
response.type('text/xml');
response.send(twiml.toString());
});
Finally, when you get the transcribe callback you can figure out the course from the transcribed text somehow and then redirect the live call into a new endpoint that carries on the call with the new information.
app.post('/transcribe', (request, response) => {
var text = request.body.TranscriptionText;
var callSid = require.body.CallSid;
// Do something with the text
var courseId = getCourseFromText(text);
var accountSid = '{{ account_sid }}'; // Your Account SID from www.twilio.com/console
var authToken = '{{ auth_token }}'; // Your Auth Token from www.twilio.com/console
var client = new twilio.RestClient(accountSid, authToken);
// Redirect the call
client.calls(callSid).update({
url: '/course?courseId=' + courseId,
method: 'POST'
}, (err, res) => {
response.sendStatus(200);
})
});

Resources