Consuming error logs with Twilio API - node.js

I have developed an application that sends thousands of SMS using Twilio Notify Service.
const bindings = phoneNumbers.map(number =>
this.createBinding('sms', number)
);
await this.notifyService.notifications.create({
toBinding: bindings,
body
});
The code above doesn't give me a feedback of whether the messages were received or not, but as I can see in Twilio dashboard, some messages fail with error codes 30005, 30003, 30006 and 52001.
I'd like to consume all those error logs and unsubscribe the numbers with error codes. I'm thinking of creating a job that runs every night to do that.
I've tried to list all the alerts:
client.monitor.alerts.each(alert => {
console.log(alert.errorCode);
});
But it seems to fetch only some alerts with error code 52001.
How can I consume all the errors with Twilio API? Is there any other way to be notified of those errors?

Related

MessageBird Whatsapp Spam Messages

After making a basic conditional change in my code I started experiencing thousands of spam messages when testing the bot I've built.
Please do consider, in my code there is no loop whatsoever to trigger this process of spam messages.
Things Ive done to try to resolve the situation but did not work:
Comment the code to send messages to the client
Restarting the server
See below for my code
var checkContact = req.body.hasOwnProperty('contact');
var registerCustomer = {
name: '',
phoneNumber: ''
};
if (checkContact) {
registerCustomer.name = req.body.contact.displayName;
registerCustomer.phoneNumber = `+${req.body.contact.msisdn}`;
}
await messageBirdWhatsAppService.sendRegistrationMessage(registerCustomer.phoneNumber);
My question is:
Does Messagebird Whatsapp API requires a response status.
Are failed rejection of webhooks result into this issue.
Can fail responses (Returning a status to the server after making a call) cause this issue
This seemed to be a messagebird issue. As I deleted the channel of the WhatsApp chatbot and still messages was coming in. I'm still awaiting messagebird support response. So I will wait for confirmation before closing this.
This is now resolved, turns out even if a webhook is not called upon it still sends a request checking for the endpoint. In future, please ensure your endpoints are active. Hence the spam messages.

how does users.watch (in gmail google api) listen for notifications?

I am confused as to how should the watch feature in the gmail API be implemented to recieve the push notificatons inside a node.js script. Should I call the method inside an infinite loop or something so that it doesn't stop listening for notifications for email once after the call is made?
Here's the sample code that I've written in node.js:
const getEmailNotification = () => {
return new Promise(async (resolve, reject) => {
try{
let auth = await authenticate();
const gmail = google.gmail({version: 'v1', auth});
await gmail.users.stop({
userId: '<email id>'
});
let watchResponse = await gmail.users.watch({
userId: '<email id>',
labelIds: ['INBOX'],
topicName: 'projects/<projectName>/topics/<topicName>'
})
return resolve(watchResponse);
} catch(err){
return reject(`Some error occurred`);
}
})
Thank you!
Summary
To receive push notifications through PUB/SUB you need to create a web-hook to receive them. What does this mean? You need a WEB application or any kind of service that exposes a URL where notifications can be received.
As stated in the Push subscription documentation:
The Pub/Sub server sends each message as an HTTPS request to the subscriber application at a pre-configured endpoint.
The endpoint acknowledges the message by returning an HTTP success status code. A non-success response indicates that the message should be resent.
Setup a channel for watch the notifications could be summarized in the following steps (the documentation you refer to indicates them):
Select/Create a project within the Google Cloud Console.
Create a new PUB/SUB topic
Create a subscription (PUSH) for that topic.
Add the necessary permissions, in this case add gmail-api-push#system.gserviceaccount.com as Pub/Sub Publisher.
Indicate what types of mail you want it to listen for via Users.watch() method (which is what you are doing in your script).
Example
I give you an example using Apps Script (it is an easy way to visualize it, but this could be achieved from any kind of WEB application, as you are using Node.js I suppose that you are familiarized with Express.js or related frameworks).
First I created a new Google Apps Script project, this will be my web-hook. Basically I want it to make a log of all HTTP/POST requests inside a Google Doc that I have previously created. For it I use the doPost() equal to app.post() in Express. If you want to know more about how Apps Script works, you can visit this link), but this is not the main topic.
Code.gs
const doPost = (e) => {
const doc = DocumentApp.openById(<DOC_ID>)
doc.getBody().appendParagraph(JSON.stringify(e, null, 2))
}
Later I made a new implementation as a Web App where I say that it is accessible by anyone, I write down the URL for later. This will be similar to deploying your Node.js application to the internet.
I select a project in the Cloud Console, as indicated in the Prerequisites of Cloud Pub/Sub.
Inside this project, I create a new topic that I call GmailAPIPush. After, click in Add Main (in the right bar of the Topics section ) and add gmail-api-push#system.gserviceaccount.com with the Pub/Sub Publisher role. This is a requirement that grants Gmail privileges to publish notification.
In the same project, I create a Subscription. I tell it to be of the Push type and add the URL of the Web App that I have previously created.
This is the most critical part and makes the difference of how you want your application to work. If you want to know which type of subscription best suits your needs (PUSH or PULL), you have a detailed documentation that will help you choose between these two types.
Finally we are left with the simplest part, configuring the Gmail account to send updates on the mailbox. I am going to do this from Apps Script, but it is exactly the same as with Node.
const watchUserGmail = () => {
const request = {
'labelIds': ['INBOX'],
'topicName': 'projects/my_project_name/topics/GmailAPIPush'
}
Gmail.Users.watch(request, 'me')
}
Once the function is executed, I send a test message, and voila, the notification appears in my document.
Returning to the case that you expose, I am going to try to explain it with a metaphor. Imagine you have a mailbox, and you are waiting for a very important letter. As you are nervous, you go every 5 minutes to check if the letter has arrived (similar to what you propose with setInterval), that makes that most of the times that you go to check your mailbox, there is nothing new. However, you train your dog to bark (push notification) every time the mailman comes, so you only go to check your mailbox when you know you have new letters.

Node.js Google PubSub Subscriber does not receive SOME messages

Summary:
I have a chat functionality in my Node.js app and want to send messages to the clients via socket.io. I trigger the emit to the client via PubSub. Now, when running the PubSub Subscription everything works (i.e. prints out messages) in roughly 70% of the cases, but would sometimes just stop and not do anything (in particular it would also not print out an error).
I can confirm that the missing 30% (messages) are being published to the topic though, as a different subscription to the same topic receives the messages.
Any help with debugging this would be highly appreciated.
Details
This is my Stack:
Node.js
socket.io
express.js
passport.js
MongoDB
react.js
Process:
Anna sends a message in chat (this writes to the database and also publishes to PubSub topic "messages")
Node.js express app runs a subscription and would then based on the message content emit to whoever else should receive the message.
BoB who is on the same channel as Anna would, in this case, receive the message.
Why do I not directly emit from Anna to Bob? The reason being that I want to have an AppEngine in between the messages and potentially add some logic there, this seemed a good way doing it.
Subscription
const pubSubClient = require('./client');
const errorHandler = function(error) {
console.error(`ERROR: ${error}`);
throw error;
};
module.exports = listenForMessages =(subscriptionName="messageReceiver",io) => {
const subscription = pubSubClient.subscription(subscriptionName);
// Listen for new messages until timeout is hit
subscription.on("message", (message) => {
console.log(`Received message ${message.id}:`);
const parsedMessage = JSON.parse(message.data)
parsedMessage._id = message.id
console.log(parsedMessage)
if (parsedMessage.to === "admin") {
io.to(`admin:${parsedMessage.from}`).emit("NewMessage", parsedMessage);
} else {
io.to(`${parsedMessage.to}`).emit("NewMessage", parsedMessage);
}
message.ack();
});
subscription.on('error', errorHandler);
}
Server.js
...
const listenForMessages = require("./message_processing/listen");
listenForMessages("messageReceiver", io);
Sample console output
The following console output was generated by running the app locally with two browsers [one in incognito] chatting with each other. It can be seen that only the very last message was actually picked up by the listener (and printed out). Funnily enough, due to the async nature of the calls, the printout of the received message came before the log that the message was sent (i.e. latency surely can't be a problem here).
[0] went into deserialize user
[0] Message 875007020424601 published.
[0] went into deserialize user
[0] Message 875006704834317 published.
[0] went into deserialize user
[0] Message 875006583857400 published.
[0] went into deserialize user
[0] Message 875006520104287 published.
[0] went into deserialize user
[0] Message 875006699141463 published.
[0] went into deserialize user
[0] Received message 875006881073134:
[0] {
[0] from: '5e949f73aeed81beefaf6daa',
[0] to: 'admin',
[0] content: 'i6',
[0] seenByUser: true,
[0] type: 'message',
[0] createdByUser: true,
[0] createdAt: '2020-04-20T07:44:54.280Z',
[0] _id: '875006881073134'
[0] }
[0] Message 875006881073134 published.
In some other cases, earlier messages work and then the listener seems to stop.
There are a couple of things you could do to check what is happening:
Go to the topic page, select the topic to see the details, and look at the publish rate. Ensure that the messages you think are being published are actually being published successfully as far as Pub/Sub is concerned. If publishes are failing, it is possible they could be delivered to one of your subscribers and not the other.
Go to the subscription page, select the subscription to see the details, and look at the "Unacked message count" and "Oldest unacked message age" graphs. If these are nonzero, then that means there are messages not getting delivered to your subscriber. If they are zero, then that means the messages are getting delivered to and acknowledged by your subscriber.
If the number of unacked messages is zero, then the likely cause is a rogue processes acting as a subscriber on the subscription receiving the messages. Perhaps a previous instance of your service is still running unexpectedly? Or possibly another task that should use a different subscription is using the same subscription.
Another thing to be aware of is that subscribers will only receive messages on subscriptions that were created before messages were published. Therefore, if you started up the publisher and published some messages and then created the subscription, say at the time when the subscriber was started up, then the subscriber will not receive those earlier messages.

Actions on Google - Handle Timeout

If the Action on Google times out, for whatever reason, there doesn't seem to be a notification/request message sent notifying the webhook of this.
On Alexa platform, a SessionEnded message is sent to the webhook.
How can I know if the assistant has timed out?
If you are using node.js in your webhook, you can use the app.catch-method. It is used to catch all unhandled errors and then it is possible to send an appropriate message. Here is an example:
app.catch((conv,error) => {
console.error(error);
conv.close("Oops, something went wrong. Our developers are trying to solve this as quickly as possible.");
})
Let me know if it worked.

Using an Azure Web Function to receive a Twilio SMS Message

I'm trying to get an Azure Web Function to receive a Twilio SMS message - and failing!
I've created a Web Function to successfully send SMS messages - now I want to listen and react to responses.
I've set up a web function as per the below. Its pretty simple at the moment, and is supposed to parrot back the original message:
public static async Task<HttpResponseMessage> Run(HttpRequestMessage req, TraceWriter log)
{
log.Info("C# HTTP trigger function processed a request.");
var data = await req.Content.ReadAsStringAsync();
var formValues = data.Split('&')
.Select(value => value.Split('='))
.ToDictionary(pair => Uri.UnescapeDataString(pair[0]).Replace("+", " "),
pair => Uri.UnescapeDataString(pair[1]).Replace("+", " "));
// Perform calculations, API lookups, etc. here
var response = new MessagingResponse()
.Message($"You said: {formValues["Body"]}");
var twiml = response.ToString();
twiml = twiml.Replace("utf-16", "utf-8");
return new HttpResponseMessage
{
Content = new StringContent(twiml, Encoding.UTF8, "application/xml")
};
}
In Twilio, I've configured the phone to use web hooks:
I've deployed the Web Function, however when I try testing by sending a message, I get the following error in the Twilio logs:
11200 There was a failure attempting to retrieve the contents of this URL
Msg Unsupported Media Type
Message: The WebHook request must contain an entity body formatted as JSON.
Does anyone have any experience in how to fix this error?
I just got this working with Twilio's SMS services. In the Azure Portal, if you go to the function, then go to Integrate, change the mode to Standard. This forces the Azure function to return a normal HTTP response and you can control the content type. If you use application/xml it will work fine.
Okay, the current solution to this is .... it can't be done in Azure Web Functions. An Azure Web Function expects a JSON payload. Twilio Webhooks are an XML value/pair. So, the web function will reject the webhook call.
The best/easiest approach is to use a WebAPI or MVC Controller as per the Twilio example. I tried a sample version and had my Twilio Webhooks working to reply to an SMS in about 15 minutes from start to finish.
To debug, I'd use a tool such as Postman or Fiddler to manually replay (or create from scratch) an identical request to what you're expecting from Twilio. You can then see what kind of response you get and not have to solely rely on Twilio's error message.
From the error code, I'd imagine that the problem is either:
Your URL set up in the Twilio number configuration isn't actually reaching your function.
Your function is taking too long to respond. Twilio will throw 11200 if it doesn't get a response in a certain time.
Your response is formatted incorrectly. This is where the aforementioned strategy can help you diagnose the issue.

Resources