How to send an email with a custom template using aws pinpoint - aws-pinpoint

I'm trying to send a email with a template and a got this error message:
Unknown parameter in Content: "Template", must be one of: Simple, Raw
I followed this link: https://boto3.amazonaws.com/v1/documentation/api/latest/reference/services/pinpoint-email.html#PinpointEmail.Client.send_email and this is my code:
client = boto3.client('pinpoint-email', region_name=AWS_REGION)
response = client.send_email(
FromEmailAddress=SENDER,
Destination={
'ToAddresses': TOADDRESSES
},
Content={
'Simple': {
'Subject': {
'Charset': CHARSET,
'Data': "SUBJECT",
},
'Body': {
'Html': {
'Charset': CHARSET,
'Data': "BODY_HTML"
},
'Text': {
'Charset': CHARSET,
'Data': "BODY_TEXT",
}
}
},
'Template': {
'TemplateArn': TEMPLATE_ARN,
'TemplateData': json.dumps(TEMPLATE_DATA)
}
}
)

Test using the SDK for Python (Boto 3) version 1.9.62 and Python version 3.6.7.

AWS_REGION = 'ap-southeast-2'
SENDER = 'sentFrom#email.com'
TOADDRESSES = ['sendTo#email.co']
TEMPLATE_ARN = 'arn:aws:mobiletargeting:ap-southeast-2:1234567890:templates/MessageTemplate-Test01/EMAIL'
TEMPLATE_DATA = {
"FirstName": "555 name",
"Activity": "doing things",
"PersonalRecord": "1.234",
"EmailSubject": "Time to Race 123"
}
client_pinpoint = boto3.client('pinpoint-email', region_name=AWS_REGION)
response_pinpoint = client_pinpoint.send_email(
FromEmailAddress=SENDER,
Destination={'ToAddresses': TOADDRESSES},
Content={'Template': {'TemplateArn': TEMPLATE_ARN, "TemplateData": json.dumps(TEMPLATE_DATA)}})
print(response_pinpoint)

Related

Add information to a spreadsheet from the Google API

I have a Typescript and Node project in which I am trying to insert the information I get from the database into the spreadsheet using the Google API V4
https://sheets.googleapis.com/v4/spreadsheets/{spreadsheetId}:batchUpdate
This is the JSON object that I get from the database:
let sheetData = [
{
"country":null,
"age":25,
"fileName":"testName1"
},
{
"country":"Spain",
"age":null,
"fileName":"testName2"
}
]
I transform it with papaparse:
const papa = require("papaparse")
let result = papa.unparse(sheetData, {
header: false,
delimiter: ';',
encoding: 'UTF-8',
})
console.log(result)
This is what I get:
;25;testName1
Spain;;testName2
This is the xml that I use from the API to add the information:
{
"requests": [
{
"pasteData": {
"coordinate": {
"sheetId": 123,
"rowIndex": 2,
"columnIndex": 1
},
"delimiter": ";",
"type": "PASTE_VALUES",
"data": ";25;testName1Spain;;testName2"
}
}
]
}
I attach a screenshot with the result of the sheet:
My problem: All the information is put in the same row, how do I have to modify the array to include line breaks and be identified by the API?
This is the JSON that works from the API by adding \n:
{
"requests": [
{
"pasteData": {
"coordinate": {
"sheetId": 123,
"rowIndex": 2,
"columnIndex": 1
},
"delimiter": ";",
"type": "PASTE_VALUES",
"data": ";25;testName1\nSpain;;testName2"
}
}
]
}
This is the result I want to achieve, but I don't know how to treat the JSON with the information I get:
I thought that in your script, how about the following sample script?
Sample script:
const sheets = google.sheets({ version: "v4", auth }); // Please use your authorization script.
let sheetData = [
{
country: null,
age: 25,
fileName: "testName1",
},
{
country: "Spain",
age: null,
fileName: "testName2",
},
];
let result = papa.unparse(sheetData, {
header: false,
delimiter: ";",
encoding: "UTF-8",
});
console.log(result);
const requests = {
requests: [
{
pasteData: {
coordinate: {
sheetId: 123, // Please set your sheet ID.
rowIndex: 2,
columnIndex: 1,
},
delimiter: ";",
type: "PASTE_VALUES",
data: result,
},
},
],
};
sheets.spreadsheets.batchUpdate(
{
spreadsheetId: "###", // Please set your Spreadsheet ID.
resource: requests,
},
(err, result) => {
if (err) {
console.log(err);
return;
}
console.log(result.data);
}
);
In this modification, your value of result is used as the data of pasteData request.
When I tested this script, I confirmed that your expected result can be obtained.

Open modal using Slack command

I have a Slack command which displays a button. When I click on this button I need to display a modal. For this, after clicking it I do this:
const dialog = {
callback_id: "submit-ticket",
elements: [
{
hint: "30 second summary of the problem",
label: "Title",
name: "title",
type: "text",
value: "teste"
},
{
label: "Description",
name: "description",
optional: true,
type: "textarea"
},
{
label: "Urgency",
name: "urgency",
options: [
{ label: "Low", value: "Low" },
{ label: "Medium", value: "Medium" },
{ label: "High", value: "High" }
],
type: "select"
}
],
submit_label: "Submit",
title: "Submit a helpdesk ticket"
};
const modalInfo = {
dialog: JSON.stringify(dialog),
token, // this is correct
trigger_id: actionJSONPayload.trigger_id
};
// This is what I get confused with...
// Method 1
slack.dialog.open(modalInfo).catch(err => {
console.log("ERROR: ", err);
});
// end method 1
// Method 2
sendMessageToSlackResponseURL(actionJSONPayload.response_url, modalInfo);
...
function sendMessageToSlackResponseURL(responseURL: any, JSONmessage: any) {
const postOptions = {
headers: {
"Content-type": "application/json"
},
json: JSONmessage,
method: "POST",
uri: responseURL
};
request(postOptions, (error: any, response: any, body: any) => {
if (error) {
console.log("----Error: ", error);
}
});
}
// end method 2
I get always Error: invalid_trigger using method1 when this trigger is something that my button is generating automatically.
Method 2 doesn't throw any error but doesn't open any modal/dialog either.
The official documentation is not quite clear and I don't know if I need to call dialog.open or views.open. Either way, the last one is not available from Slack package
This is also the button I'm displaying before anything:
const message = {
attachments: [
{
actions: [
{
name: "send_sms",
style: "danger",
text: "Yes",
type: "button",
value: "yes"
},
{
name: "no",
text: "No",
type: "button",
value: "no"
}
],
attachment_type: "default",
callback_id: "alert",
color: "#3AA3E3",
fallback: "We could not load the options. Try later",
text: "Do you want to alert by SMS about P1 error/fix?"
}
],
text: "P1 SMSs"
};
Copy a modal from here
const headers = {
headers: {
"Content-type": "application/json; charset=utf-8",
"Authorization": "Bearer " + token
}
};
const modalInfo = {
"token": token,
"trigger_id": reqBody.trigger_id,
"view": slack.modal
};
axios
.post("https://slack.com/api/views.open", modalInfo, headers)
.then(response => {
const data = response.data;
if (!data.ok) {
return data.error;
}
})
.catch(error => {
console.log("-Error: ", error);
});
But most importantly, when we do some changes to our app we need to reinstall it and also when we do it, the token changes and this is something I couldn't find on the documentation

FCM iOS: Push notifications throw invalid argument

I am attempting to implement pushNotifications using Cloud Functions and FCM for iOS but I am consistently thrown this error:
2018-05-21T13:04:00.087Z I sendPushNotifications: Error sending
message: { Error: Request contains an invalid argument.
at FirebaseMessagingError.Error (native)
at FirebaseMessagingError.FirebaseError [as constructor] (/user_code/node_modules/firebase-admin/lib/utils/error.js:39:28)
at FirebaseMessagingError.PrefixedFirebaseError [as constructor] (/user_code/node_modules/firebase-admin/lib/utils/error.js:85:28)
at new FirebaseMessagingError (/user_code/node_modules/firebase-admin/lib/utils/error.js:241:16)
at Function.FirebaseMessagingError.fromServerError (/user_code/node_modules/firebase-admin/lib/utils/error.js:271:16)
at /user_code/node_modules/firebase-admin/lib/messaging/messaging-api-request.js:149:50
at process._tickDomainCallback (internal/process/next_tick.js:135:7) errorInfo: { code:
'messaging/invalid-argument',
message: 'Request contains an invalid argument.' }, codePrefix: 'messaging' }
My implementation in cloud functions are as follows:
exports.sendPushNotifications = functions.database.ref('/conversations/{userUid}/').onWrite((snap, context) => {
const userUid = context.params.userUid
console.log("Triggered user ", userUid)
return admin.database().ref('/fcmToken/' + userUid).once('value', snapshot => {
const values = snapshot.val()
const fcmToken = values.fcmToken
var message = {
"token": fcmToken,
"notification": {
"body": "New message"
},
"apns": {
"headers": {
"apns-priority": "5"
},
"payload": {
"aps": {
"alert": {
"body": "New message"
},
"badge": "1",
"sound": "default"
}
}
}
};
return admin.messaging().send(message)
.then((response) => {
return console.log('Successfully sent message:', response);
})
.catch((error) => {
return console.log('Error sending message:', error);
});
})
})
The frustrating thing is that when I remove the whole "apns" node the code actually works, ie I can receive the push notifications. I suppose this means my setup are all done properly. Once I included the "apns", it starts throwing the above error. I also reference these three posts, this, this and this, and made sure that I have carefully followed the code and instructions. For some reasons I cannot get it to work.
I also attempted to remove the "notification" node as the docs did mention that only use common keys when targetting all platforms. Since I am targetting only iOS for now, I suppose I should remove the "notification" key. But again it also throws the same error.
Ok, so it was a rookie mistake. It is correct that common keys should not be used if I am targetting iOS only. In addition to that, the badge should be an Int and not String.
This code worked:
var message = {
"token": fcmToken,
"apns": {
"headers": {
"apns-priority": "5"
},
"payload": {
"aps": {
"alert": {
"body": "New message"
},
"badge": 1,
"sound": "default"
}
}
}
}
Hope it helps anyone out there facing the same problem.
Just to add to this answer. If you are using both IOS and android while having custom sounds for both, the code below will work cross platform and avoid this issue.
const payload = {
token,
notification: {
title: `title text`,
body: `body text`,
},
android: {
// android
priority: "high", // legacy HTTP protocol (this can also be set to 10)
notification: {
channel_id: "call1",
priority: "high", // HTTP v1 protocol
notification_priority: "PRIORITY_MAX",
sound: "sound",
default_sound: true,
visibility: "PUBLIC",
},
},
apns: {
// apple
headers: { "apns-priority": "10" },
payload: {
aps: {
// If present with notification: {...}, this will create errors
// "alert": {
// "title": `title text`,
// "body": `body text`,
// },
badge: 1,
sound: {
critical: 1,
name: "sound.aiff",
volume: 1,
},
category: "call1",
},
},
},

Facebook messenger platform: generic template with quick replies

I was looking at some pretty popular bots like "The Guardian" and i noticed that whenever you get a generic template reply from it it also displays some quick reply buttons (see the photo attached). How did "The Guardian Bot" achieve this? How he combined quick replies and a generic template? It must be two messages involved.
This worked for me in Dialogflow, return similar Json Object in backend to achieve the result:
{
"facebook": {
"attachment":{
"type":"template",
"payload":{
"template_type":"generic",
"elements":[
{
"title":"Welcome!",
"image_url":"https://petersfancybrownhats.com/company_image.png",
"subtitle":"We have the right hat for everyone.",
"default_action": {
"type": "web_url",
"url": "https://petersfancybrownhats.com/view?item=103",
"webview_height_ratio": "tall"
},
"buttons":[
{
"type":"web_url",
"url":"https://petersfancybrownhats.com",
"title":"View Website"
},{
"type":"postback",
"title":"Start Chatting",
"payload":"DEVELOPER_DEFINED_PAYLOAD"
}
]
}
]
}
},
"quick_replies":[
{
"content_type":"text",
"title":"Search",
"payload":"<POSTBACK_PAYLOAD>",
"image_url":"http://example.com/img/red.png"
},
{
"content_type":"location"
}
]
}
}
Quick replies are usually accompanied by a 'text' property that sends a text message before the quick reply. It appears you can substitute any template for that. For example, here is the request body for a generic template carousel with quick replies:
{
"recipient":{
"id":"{{PSID}}"
},
"messaging_type": "response",
"message":{
"quick_replies": [
{
"content_type":"text",
"title":"Quick Reply 1",
"image_url":"https://raw.githubusercontent.com/fbsamples/messenger-platform-samples/master/images/Messenger_Icon.png",
"payload":"payload1"
},
{
"content_type":"text",
"title":"Quick Reply 2",
"payload":"payload2"
}
],
"attachment":{
"type":"template",
"payload":{
"template_type":"generic",
"elements":[
{
"title":"This is a generic template",
"subtitle":"Plus a subtitle!",
"image_url":"https://raw.githubusercontent.com/fbsamples/messenger-platform-samples/master/images/Messenger_Icon.png",
"buttons":[
{
"type":"postback",
"title":"Postback Button",
"payload":"<POSTBACK_PAYLOAD>"
}
]
},
{
"title":"Another generic template",
"subtitle":"Plus a subtitle!",
"image_url":"https://raw.githubusercontent.com/fbsamples/messenger-platform-samples/master/images/Messenger_Icon.png",
"buttons":[
{
"type":"postback",
"title":"Postback Button",
"payload":"<POSTBACK_PAYLOAD>"
}
]
},
{
"title":"And another!",
"subtitle":"Plus a subtitle!",
"image_url":"https://raw.githubusercontent.com/fbsamples/messenger-platform-samples/master/images/Messenger_Icon.png",
"buttons":[
{
"type":"postback",
"title":"Postback Button",
"payload":"<POSTBACK_PAYLOAD>"
}
]
}
]
}
}
}
}
I have implemented the bot in nodejs and I am using a node module called messenger-bot which makes it easier to call the messenger bot API. Here's my customized code for you
const http = require('http')
const https = require('https')
const Bot = require('messenger-bot')
var bot = new Bot({
token: 'your FB app token',
verify: 'VERIFY_TOKEN'
})
bot.on('postback', (payload, reply) => {
var postback = payload.postback.payload;
if (postback == "yes") {
function getQuickReplies() {
console.log("in next function");
var quick_list = {
"text": "Check the next article?",
"quick_replies": [{
"content_type": "text",
"title": "More stories",
"payload": "more stories"
},
{
"content_type": "text",
"title": "Sport",
"payload": "sport"
},
{
"content_type": "text",
"title": "Business",
"payload": "business"
}
]
};
bot.getProfile(payload.sender.id, (err, profile) => {
if (err) throw err
text = quick_list;
bot.sendMessage(payload.sender.id, text) {//this prints quick replies
console.log("sending message");
}
});
}
//calling generic template
var generic_temp = "message": {
"attachment": {
-- - your code-- -
}
}; //generic template refer - https://developers.facebook.com/docs/messenger-platform/send-api-reference/generic-template
bot.getProfile(payload.sender.id, (err, profile) => {
if (err) throw err
bot.sendMessage(payload.sender.id, generic_temp) {//this prints generic template
console.log("sending message");
}
});
//calling the quick replies once the generic template is sent
getQuickReplies(); //to avoid async execution issue, we will have to put this in a function.
}
});
references - Generic template, Quick replies, messenger-bot npm
Hope this helps! Happy coding ;)
NEW UPDATE
{
"facebook": {
"attachment":{
"type":"template",
"payload":{
"template_type":"generic",
"elements":[
{
"title":"Welcome!",
"image_url":"https://petersfancybrownhats.com/company_image.png",
"subtitle":"We have the right hat for everyone.",
"default_action": {
"type": "web_url",
"url": "https://petersfancybrownhats.com/view?item=103",
"webview_height_ratio": "tall"
},
"buttons":[
{
"type":"web_url",
"url":"https://petersfancybrownhats.com",
"title":"View Website"
},{
"type":"postback",
"title":"Start Chatting",
"payload":"DEVELOPER_DEFINED_PAYLOAD"
}
]
}
]
}
},
"quick_replies":[
{
"content_type":"text",
"title":"Red",
"payload":"<POSTBACK_PAYLOAD>",
"image_url":"http://example.com/img/red.png"
},{
"content_type":"text",
"title":"Green",
"payload":"<POSTBACK_PAYLOAD>",
"image_url":"http://example.com/img/green.png"
}
]
}
}

Error when trying to send transactional email from template using sendGrid

I'm trying to send a transactional email via node using sendGrid. Below is an example of my code.
const subject = 'Email subject';
const templateId = 'templateId';
const sg = require('sendgrid')(secret);
const request = sg.emptyRequest({
method: 'POST',
path: '/v3/mail/send',
body: {
"personalizations": [
{
"bcc": userEmails,
"substitutions": {
"-userName-": userDetails.name,
"-productPrice-": productDetails.price,
"-productUrl-": productDetails.url,
"-productPercentageDrop-": productDetails.percentageDrop,
"-productName-": productDetails.name,
"-productOriginalPrice-": productDetails.origPrice,
"-productDroppedPrice-": productDetails.dropPrice,
"-productImageUrl-": productDetails.imageUrl
},
"subject": subject.substring(0, 75)
}
],
"from": {
"email": "myemail",
"name": "myname"
},
"content": [
{
"type": "text/html"
}
],
"template_id": templateId
}
});
sg.API(request, function (error, response) {
if (error) {
console.log('Error response received');
}
console.log(response.body.errors);
});
But every time I run the code I get the following error message.
400
message: 'Bad Request', field: null, help: null
Which isn't really that helpful when trying to find out why its erroring.
Body JSON being sent:
{
"host":"",
"method":"POST",
"path":"/v3/mail/send",
"headers":{
},
"body":{
"personalizations":[
{
"bcc":[
{
"email":"name1#hotmail.com",
"name":"name1"
},
{
"email":"name2#hotmail.com",
"name":"name2"
}
],
"substitutions":{
"-productPrice-":189.5,
"-productUrl-":"http://www.tesco.com/direct/humax-fvp-4000t500-m-smart-freeview-play-hd-digital-tv-recorder-with-wi-fi-500gb/483-1785.prd",
"-productName-":"Tesco direct: Humax FVP-4000T/500 (M) Smart Freeview Play HD Digital TV Recorder with Wi-Fi - 500GB"
},
"subject":"Product Tesco direct: Humax FVP-4000T/500 (M) Smart Freeview Play HD Digita"
}
],
"from":{
"email":"email#pricetracker.io",
"name":"Pricetracker"
},
"content":[
{
"type":"text/html"
}
],
"template_id":"XXXXXX"
},
"queryParams":{
},
"test":false,
"port":""
}
don't know if this could still be helpful for you, but I've had some similar issues when using substitutions with Sendgrid. I'm using the sendgrid-php library, but internally it sends the same format. What I found was that all substitution values should be converted to string. For instance your value for productPrice should be like this:
"-productPrice-": "189.5",
With quotes. In my case I had integers, and when I converted them to strings, all worked correctly.
If you are not passing string value to the template file then SendGrid will give you
{"errors":[{"message":"Bad Request","field":null,"help":null}]}
Convert your all non-string value to string before sending to the template file.
I got same issue, then I fix using this below syntax, change only you message format.
"value": "'.html_entity_decode((str_replace('"',"'",$message))).'"

Resources