Twilio Studio Function to Send Voicemail URL - twilio

I am using Twilio Studio for to collect messages for our small church. When someone records a voicemail, I am using a function to send the recording URL to the group members. Here is what that function looks like currently:
var groupmembers = [
{
name: 'Person1',
number: '+11111111111'
},
{
name: 'Person2',
number: '+11111111111'
}
];
exports.handler = function(context, event, callback) {
let twiml = new Twilio.twiml.MessagingResponse();
groupmembers.forEach(function(member) {
// Now, forward on the message to the group member, using the sender's name
twiml.message(`Text from ${event.senderFrom}: ${event.senderMessage}`, {
to: member.number
});
})
callback(null, twiml);
};
This gives me a '12200 Schema validation warning' with the detail: Invalid content was found starting with element 'Message'. One of '{Play
I'm fairly sure the issue is because I am trying to send an SMS during a call but I am not sure how to update my TWIML or Studio flow to accommodate for this.
Any help is appreciated!

you need the REST API rather then TwiML in this case. You could use code similar to what is shown below to do this.
Make sure to check the box below, under Function Config for your Function,
exports.handler = function(context, event, callback) {
const twilioClient = context.getTwilioClient();
let groupMembers = [
{
name: 'Person1',
number: '+14701111111'
},
{
name: 'Person2',
number: '+18082222222'
},
{
name: 'Person3',
number: '+18021111111'
}
];
function sendSMS(member) {
return twilioClient.messages.create({
from: '+13054444444',
to: member.number,
body: 'Hello World!'
});
}
let promises = [];
groupMembers.forEach((member) => {
console.log(member);
promises.push(sendSMS(member));
});
Promise.all(promises)
.then((values) => {
console.log(values);
callback(null,"Success");
})
.catch(error => {
console.log(error);
callback("Failure");
});
};

Related

Twilio Functions - Pass in parameters and format SMS body to include parameters

I am using Twilio to create an 'attendance line' where employees can provide information about why they will be absent and then Twilio will send separate, curated messages to supervisors and human resources.
To do this, I've created a Flow in Twilio Studio and I would like to use a Twilio Function to handle sending the mass SMS messages notifying users of a new absence.
I am passing parameters to the function like name, dept, shift, reason, etc with the intent to then share these values via SMS.
I am having the hardest time getting all of these different values properly into the body of the message.
exports.handler = function(context, event, callback) {
// Create a reference to the user notification service
const client = context.getTwilioClient();
const service = client.notify.services(
context.TWILIO_NOTIFICATION_SERVICE_SID
);
const notification = {
toBinding: JSON.stringify({
binding_type: 'sms', address: '+1XXXXXXXXXX',
binding_type: 'sms', address: '+1XXXXXXXXXX',
}),
body: 'New Attendance Notification',
event.question_name,
event.question_dept,
event.question_reason,
event.contactChannelAddress,
};
console.log(notification);
// Send a notification
return service.notifications.create(notification).then((message) => {
console.log('Notification Message',message);
callback(null, "Message sent.");
}).catch((error) => {
console.log(error);
callback(error,null);
});
};
Now I know the 'body' of the message above will not work but I'm a bit lost...
The text below is how I would like my SMS message to read out when sent.
New Attendance Notification
Name: event.Name
Dept: event.Dept
Reason: event.Reason
Contact: event.ContactChannelAddress
Is what I am trying to accomplish even possible?
Something like this...
exports.handler = function(context, event, callback) {
// Create a reference to the user notification service
const client = context.getTwilioClient();
const service = client.notify.services(
context.TWILIO_NOTIFICATION_SERVICE_SID
);
const bindings = [
'{ "binding_type": "sms", "address": "+14071234567" }',
'{ "binding_type": "sms", "address": "+18021234567" }'
];
const notice = `New Attendance Notification\nName: ${event.question_name}\nDept: ${event.question_dept} \nReason: ${event.question_reason}\nContact: ${event.contactChannelAddress} \n`;
// Send a notification
service.notifications.create({ toBinding: bindings, body: notice }).then((message) => {
console.log('Notification Message',message);
callback(null, "Message sent.");
})
.catch((error) => {
console.log(error);
callback(error,null);
});
};

Parse JSON into array javascript with Twilio Function

Attempting to create a chat bot that will hit a web service midway through and ask questions based on previous responses.
I have created a function that will return an array of people that I will then text these names and ask the user to pick one.
Twilio Function
exports.handler = function(context, event, callback) {
const employees = [{ name: 'Mark', id:15 }, { name: 'Scott', id:16 }, { name: 'Steve', id:17 }];
callback(null, employees);
};
I would hope this would return function_1.parsed values, but everything is stored in function_1.body and I can't access it the way I hoped.
Here's a view of my Log.
Anyone know how I can send this to Parsed instead of body? If I submit a simple object it will return to the parsed value.
exports.handler = function(context, event, callback) {
const employee = { name: 'Mark', id:15 };
callback(null, employee);
};
here is the trick, Wrap it in an object:
{"result":
[{ name: 'Mark', id:15 }, { name: 'Scott', id:16 }, { name: 'Steve', id:17 }]
};

Twilio - Send email from function

Is there a way to send email from Twilio function? I understand that we can use sendgrid. I am looking a simpler solution.
Twilio evangelist here. 👋
As of now, you can use SendGrid from within a Twilio Function. The code below does the job for me and I just sent an email via a function
exports.handler = function(context, event, callback) {
const sgMail = require('#sendgrid/mail');
sgMail.setApiKey(process.env.SENDGRID_API_KEY);
const msg = {
to: 'sjudis#twilio.com',
from: 'test#example.com',
subject: 'Sending with SendGrid is Fun',
text: 'and easy to do anywhere, even with Node.js',
html: '<strong>and easy to do anywhere, even with Node.js</strong>',
};
sgMail.send(msg)
.then(() => {
callback(null, 'Email sent...');
})
.catch((e) => {
console.log(e);
})
};
The above email will most like end up in spam as test#example.com is not a very trust worthy email address. If you want to send emails from your own domains additional configuration is needed.
To run the code inside of the function, you have to make sure to install the sendgrid/mail mail dependency and provide the sendgrid token in the function configuration.
If you want to use this function to power e.g. messages you have to make sure that your return valid TwiML. :) When you create a new function you will get examples showing on how to do that.
Hope that helps. :)
Another way is to use the SendGrid API
const got = require('got');
exports.handler = function(context, event, callback) {
const requestBody = {
personalizations: [{ to: [{ email: context.TO_EMAIL_ADDRESS }] }],
from: { email: context.FROM_EMAIL_ADDRESS },
subject: `New SMS message from: ${event.From}`,
content: [
{
type: 'text/plain',
value: event.Body
}
]
};
got.post('https://api.sendgrid.com/v3/mail/send', {
headers: {
Authorization: `Bearer ${context.SENDGRID_API_KEY}`,
'Content-Type': 'application/json'
},
body: JSON.stringify(requestBody)
})
.then(response => {
let twiml = new Twilio.twiml.MessagingResponse();
callback(null, twiml);
})
.catch(err => {
callback(err);
});
};
};
Source: https://www.twilio.com/blog/2017/07/forward-incoming-sms-messages-to-email-with-node-js-sendgrid-and-twilio-functions.html

Twilio Autopilot: How to pull data from Airtable and return results to user?

I'm using Collect in the first Autopilot task to get the date from the user (i.e. Jan 31, 2019). Then I am trying to use that variable (date) to search an Airtable database for that specific row. I want to return the results of that row to the user ("on Jan 31 the Main Theater is playing this movie, the Other Theater is playing...).
My Airtable Get code is below, but I am unsure how to assign the returned data to variables that I can read back to the user.
exports.handler = function(context, event, callback) {
var Airtable = require('airtable');
var base = new Airtable({apiKey:
'apikey'}).base('basekey');
base('Blockouts').find('recbGHAQopLQdCOHK', function(err, record) {
if (err) { console.error(err); return; }
console.log(record);
});
}
and here's the output that Airtable will send back:
{
"id": "recbGHAQopLQdCOHK",
"fields": {
"Date": "2019-02-02",
"Main Theater": "Star Wars",
"Other Theater": "Avengers"
},
"createdTime": "2019-02-02T21:21:48.000Z"
}
Twilio evangelist here.
If your Airtable Get code is not there already, it should go in a Twilio function (which supports Node.js)! that is pointed at an Autopilot task whose actions code has something like this:
{
"actions": [
{
"redirect": {
"uri": "https://your-twilio-function-path.twil.io/airtable-or-whatever-if-this-is-your-path"
}
}
]
}
Then in your Twilio function/Airtable Get code, you should modify your Twilio Response object to accept all requesting origins and have that look something like this:
exports.handler = function(context, event, callback) {
let response = new Twilio.Response();
let headers = {
"Access-Control-Allow-Origin": "*",
"Content-Type": "application/json"
};
var responseObject = {"actions":[
{ "say": "Try again" }
]};
response.setHeaders(headers);
var Airtable = require('airtable');
var base = new Airtable({apiKey: 'apikey'}).base('basekey');
base('Blockouts').find('recbGHAQopLQdCOHK', function(err, record) {
if (err) { console.error(err); return; }
console.log(record);
}).then(res => {
var date = res.data[0].fields.date;
responseObject = {"actions":[
{ "say": date }
]};
callback(null, responseObject);
});
};
I have not tested this code with your Airtable output (famous last words of a programmer), but used almost exactly the same code when making an Axios request to an API where I saved some of the data returned from that call in a variable, so it should be similar.
Hope this helps.

Twilio call function - Always repeating "Please enter your ID"?

Here's my code
exports.handler = function(context, event, callback) {
let twiml = new Twilio.twiml.VoiceResponse();
let gather = twiml.gather({
input: 'dtmf',
finishOnKey: '#'
});
gather.play("Please enter your user ID");
callback(null, twiml);
var got = require('got');
var requestPayload = event;
got.post('http://www.test.com/test.php?test=' + JSON.stringify(requestPayload), {
body: JSON.stringify(requestPayload),
headers: {
'accept': 'application/json'
},
json: true
})
.then(function(response) {
console.log(response.body)
callback(null, response.body);
})
.catch(function(error) {
callback(error)
})
};
I got successful response from url , but i need to ask second question . How to continue from here.
Thanks
Twilio developer evangelist here.
If you want to use just the one function for this, then you need it to do different things depending on whether the user has just called or if they have entered some digits.
I've rearranged your code a bit and left comments to guide you:
const got = require('got');
exports.handler = function(context, event, callback) {
// We can set up our initial TwiML here
let twiml = new Twilio.twiml.VoiceResponse();
let gather = twiml.gather({
input: 'dtmf',
finishOnKey: '#'
});
if(event.Digits) {
// The user has entered some digits to answer the question so we post to
// your API and only callback when we get the results
got.post('http://www.test.com/test.php', {
body: JSON.stringify(event),
headers: {
'accept': 'application/json'
},
json: true
})
.then(function(response) {
// Check the response and ask your second question here
gather.say("Please enter your case ID.");
callback(null, twiml);
})
.catch(function(error) {
// Boo, there was an error.
callback(error)
});
} else {
// The user hasn't entered anything yet, so we ask for user ID
gather.say("Please enter your user ID");
callback(null, twiml);
}
};
Let me know how that works for you. You might find that if you then need to do even more work that a single Function is not the best idea here and you should direct the user to a new Function to continue the call after the case ID is entered.
Let me know if this helps at all.

Resources