How to send email using sendgrid in Nodejs using dynamicTemplateData? - node.js

This my first time I use sendgrid for mail. I have problem with dynamic data passed from database. Actually HTML content passed in object and display as it is in mail. For more detail check below object.
{
to: "to Email"
from: "from email",
templateId: "Template ID",
dynamicTemplateData: {
subject: "Testing Templates",
name: "Some One",
city: "Denver",
week: "August 24 2020",
job0: {
header: "Test",
body: "<table border="0" cellspacing="0" cellpadding="0"> <tbody> <tr> <td class="
snip ">We are looking for physically fit individuals to fill general labour requirements by partnering with a truck driver. Your help is needed to load/unload the truck at the various job sites. <b>Skills required: </b> - comfortable with physical exertion and lifting minimum of 50lbs - works well on a team but trusted to work independently - reliable, self-motivated and committed to high standards of quality - able to read and understand work instructions <b>Specific requirements: </b> - in good physical condition - must have own safety footwear - reliable transportation to ensure punctual and consistent attendance If you meet the qualifications listed above, submit your resume in MS Word format via the link below. <i>Previously employed with The Staffing Connection? Please contact our office to confirm your continued availability for these upcoming positions.</i></td> </tr> </tbody> </table>",
cta: "Apply now",
url: "My URL"
},
}
}
Code
getJobs().then((jobs) => {
var mailPayload = {
to: emails,
from: "",
templateId: "",
dynamicTemplateData: {
subject: "Testing Templates",
name: "Some One",
city: "Denver",
week: "August 24 2020",
},
};
for (let i = 0; i < jobs.length; i++) {
mailPayload.dynamicTemplateData["job" + i] = {
header: jobs[i].job_title,
body: jobs[i].job_description,
cta: "Apply now",
url: jobs[i].company_url,
};
}
mail(mailPayload);
res.send("Mail sent Successfully").status(200);
});
});
Here is the Output
Please help me to solve this issue.

Related

Error using SharePoint REST API endpoint for creating a Modern Teams site: The parameter request does not exist in method CreateGroupEx

The bounty expires in 5 days. Answers to this question are eligible for a +50 reputation bounty.
arresteddevelopment wants to draw more attention to this question.
I am trying to use the SharePoint REST API endpoint _api/GroupSiteManager/CreateGroupEx to create a SharePoint Modern Teams site
url: /_api/GroupSiteManager/CreateGroupEx
accept: application/json;odata.metadata=none
odata-version: 4.0
method: POST
body:
{
"request": {
"Title": "Communication Site 1",
"Url":"https://contoso.sharepoint.com/sites/commsite1",
"Lcid": 1033,
"ShareByEmailEnabled":false,
"Classification":"Low Business Impact",
"Description":"MyDescription",
"WebTemplate":"STS#3",
"SiteDesignId":"6142d2a0-63a5-4ba0-aede-d9fefca2c767",
"Owner":"owner#yourtenant.onmicrosoft.com"
}
}
I have proven my API process by creating a Modern Communication site with the endpoint /_api/SPSiteManager/create and "WebTemplate":"SITEPAGEPUBLISHING#0"
When I attempt to create the Modern Teams site I get the error:
Failed: {"error":{"code":"-1, Microsoft.SharePoint.Client.InvalidClientQueryException","message":{"lang":"en-US","value":"The parameter request does not exist in method CreateGroupEx."}}}
Try to update the request body like below:
body:{
"request": {
alias: "Communication Site 1",
displayName: "Communication Site 1",
isPublic: true,
optionalParams: {
Classification: "Low Business Impact",
CreationOptions: [`SPSiteLanguage:1033`,`implicit_formula_292aa8a00786498a87a5ca52d9f4214a_6142d2a0-63a5-4ba0-aede-d9fefca2c767`],
Description: "MyDescription",
Owners: "owner#yourtenant.onmicrosoft.com"
}
}
}
Also I have noticed that changing the Accept to below helps:
'Accept': 'application/json;odata.metadata=minimal'
It clearly complains about the "request" parameter, telling that there is no such parameter. Worked for me:
url: /_api/GroupSiteManager/CreateGroupEx
accept: application/json
method: POST
body: {
"alias": "CommunicationSite1",
"displayName": "Communication Site 1",
"isPublic": true,
"optionalParams": {
"CreationOptions": [
"SPSiteLanguage:1033",
"implicit_formula_292aa8a00786498a87a5ca52d9f4214a_6142d2a0-63a5-4ba0-aede-d9fefca2c767"
],
"Description": "MyDescription",
"Owners": ["owner#yourtenant.onmicrosoft.com"]
}
}
Some notes:
alias should not contain spaces (it is a part of url and email nickname)
I have no idea what the classification could be, just omited (your string does not seem work)
owners should be an array, not a string

Schema for inheriting content from central down to subsidiary

We have a content model where we set content at a central level, but users have the ability to edit the content down to subsidiary level if they want to. If they don't want to change anything from what gets set from central they don't have to.
Let's assume a simple api endpoint that just takes in companyId. This is how it would respond:
GET /offers (central values)
[{
offerId: 1,
title: "Central offer title",
paragraph: "Lorem ipsum central",
price: 100
}, {...more offers}]
Company 123
/offers?companyId=123
[{
offerId: 1,
title: "Company offer title",
paragraph: "Lorem ipsum central", // Inherited from central
price: 125
}, {...more offers}]
Company 456 which is a subsidiary to 123
/offers?companyId=456
[{
offerId: 1,
title: "Company offer title", // Inherited from Company 1
paragraph: "Lorem ipsum subsidiary",
price: 125, // Inherited from Company 1
custom_field: "A completely custom field for subsidiary" // Field only available for subsidiary
}, {...more offers}]
In previous implementations we have done something in the lines of:
{
offerId: 1,
values: [
{
companyId: null,
title: "Central offer title",
paragraph: "Lorem ipsum central",
price: 100
},
{
companyId: 123,
title: "Company offer title",
price: 125
},
{
companyId: 456,
paragraph: "Lorem ipsum subsidiary",
custom_field: "A completely custom field for subsidiary"
}
]
}
And then in the application we have compiled this down so values are specific for subsidiary, but still inheriting data from central or parent company.
Now that we're about to write new applications that should once again allow this type of content inheritance, we're having doubts about this approach and wonder if there's another way to model this.
What other ways exist to model this type of behavior?
Are you using mongoose? If so - use Discriminators:
const event1 = new Event({ time: Date.now() });
const event2 = new ClickedLinkEvent({ time: Date.now(), url: 'google.com' });
const event3 = new SignedUpEvent({ time: Date.now(), user: 'testuser' });
More on that topic in this fine read: https://dev.to/helenasometimes/getting-started-with-mongoose-discriminators-in-expressjs--22m9
If not - then I think you should follow the same approach as in mongoose - have each company as a separate document. Because in your old setup, there are a few things:
Company resides in Offer document
If multiple offers use the same companies, you'd duplicate company data, right?
There's no easy way to search for company - you get offers.values and search for a property inside. That's basically traversing your entire database.
If you only search by company (and not offer ID as you said), you can reverse them. But it's still weird. I'd split them in two separate things and use references between them. This way you could:
Find company by id
Find it's parent (do this until there is no parent; use aggregate to make it in a single query)
Get a list of offers for that company (document property) and query them
This approach would allow you to do the opposite (offer to company).

Can we trigger the simple response after the list response is displayed in the Dialogflow?

Whenever the user invokes my agent then it shows a list of options to select and also a simple response but the agent first speaks the simple response and then shows the list
Actual
user: Ok google talk to my test app.
bot: Welcome to my test app, Here's the list of options to select. (WELCOME MESSAGE)
Please select your preference (RESPONSE)
<list appears> (LIST)
Expected
user: Ok google talk to my test app.
bot: Welcome to my test app, Here's the list of options to select. (WELCOME MESSAGE)
<list appears> (LIST)
Please select your preference. (RESPONSE)
Is it possible that the assistant first speaks the welcome message,shows the list and then speaks out the response after a certain delay?
No, showing the bubble after the list is not possible.
When you add a list to your response, the spoken text will always appear before the list. This is mainly due to the fact that the spoken/chat part of the conversation is separate from the visual part of your conversation. Even when adding the response after the list in your code, the displaying of rich response is controlled by Google.
Example:
conv.ask('This is a list example.');
// Create a list
conv.ask(new List({
title: 'List Title',
items: {
'SELECTION_KEY_ONE': {
synonyms: [
'synonym 1',
'synonym 2',
'synonym 3',
],
title: 'Title of First List Item',
description: 'This is a description of a list item.',
image: new Image({
url: 'https://storage.googleapis.com/actionsresources/logo_assistant_2x_64dp.png',
alt: 'Image alternate text',
}),
},
'SELECTION_KEY_TWO': {
synonyms: [
'synonym 4',
'synonym 5',
'synonym 6',
],
title: 'Title of Second List Item',
description: 'This is a description of a list item.',
image: new Image({
url: 'https://storage.googleapis.com/actionsresources/logo_assistant_2x_64dp.png',
alt: 'Image alternate text',
}),
}
}
}));
conv.ask("Please make your selection");
By the look of your example it seems as if you are trying to show the user a couple options on the screen to control the conversation, are you sure Suggestion Chips wouldn't be a better fit for this? These chips are intended to give the user options and are far easier to implement than a list.
Delaying the speech, not the bubble
If you don't want to go that way, what you could do, is add an delay in the spoken text via SSML, but this would only change the experience for people using your action via voice. It wouldn't change the display location of the speech bubble when using the Google Assistant on your phone. For anyone using your action without a screen, this could cause confusion because the speech is being delayed for a list, which is never going to show on their device since it has no screen.
Design in a voice first experience
In general it is a good practice to design your conversation around the voice only part of your conversation. By making your conversation dependable on a list, you limit the amount of platforms you can deploy your action to. A voice first approach to this problem could be to create intents for each option your action supports and opening your welcome intent with a generic message such as "How can I assist you?" and having a fallback intent in which you assist the user by speaking out the different options that they can use. This could be combined with Suggestion Chips to still give the guiding visuals that you desire.
It is a bit more work to implement, but it does give your bot a great more amount of flexibility in its conversation and the amount of platforms it can support.
Add webhook to your action and use the Browsing Carousel JSON for the intent. Add simpleReponse node after the list items to add a response after list is displayed. Sample JSON for Browsing Carousel:
{
"payload": {
"google": {
"expectUserResponse": true,
"richResponse": {
"items": [
{
"simpleResponse": {
"textToSpeech": "Here's an example of a browsing carousel."
}
},
{
"carouselBrowse": {
"items": [
{
"title": "Title of item 1",
"openUrlAction": {
"url": "https://example.com"
},
"description": "Description of item 1",
"footer": "Item 1 footer",
"image": {
"url": "https://storage.googleapis.com/actionsresources/logo_assistant_2x_64dp.png",
"accessibilityText": "Image alternate text"
}
},
{
"title": "Title of item 2",
"openUrlAction": {
"url": "https://example.com"
},
"description": "Description of item 2",
"footer": "Item 2 footer",
"image": {
"url": "https://storage.googleapis.com/actionsresources/logo_assistant_2x_64dp.png",
"accessibilityText": "Image alternate text"
}
}
]
}
}
]
}
}
}
}
Refer to https://developers.google.com/assistant/conversational/rich-responses#df-json-basic-card

Nodejs handlebar render empty webpage

I'm a newbie in nodejs and i'm learning to use handlebars to render a website.
Here is my routing (inside index.js)
app.get('/house', function (req, res) {
var houses = [
{
name: "House a",
address: "Address a",
price: "Price a"
},
{
name: "House b",
address: "Address b",
price: "Price b"
},
{
name: "House c",
address: "Address c",
price: "Price c"
}
]
res.render('house', houses);
})
Here is my house.handlebars
<div class="row">
{{#each houses}}
<div class="col-md-3 col-lg-3">
<p>Name: {{name}}</p>
<p>Address: {{address}}</p>
<p>Price: {{price}}</p>
</div>
{{/each}}
</div>
The problem is when i go to http://localhost:3000/house, the page is all white and render nothing. I inspected the site and notice that everything inside {{each houses}} and {{/each}} disappear.
I'm wondering what are the problems here.
Many thanks
Your object structure is incorrect. try this:
res.render('house', {houses: houses});

Sendgrid Substitutions Tags

I want to send a notification email in my application and I am trying to use sendgrid. My application is writtin in CoffeeScript.
enter code here
from_address = 'noreply#example.co'
subject = 'This Is The Subject'
html_body = '<table style="font-family: verdana, tahoma, sans-serif; color: #000;">
<tr> <td>
<h2>Hello,</h2> <p>Hello!!</p>
<p>%%name%% %%surname%% send you a message</p>
</table>'
sendgrid = require('sendgrid')(api_key)
Email = sendgrid.Email
email = new Email(
to: to_address
from: from_address
subject: subject
text: text_body
html: html_body)
recipients = [
'example1#example.com'
'example2#example.com'
]
i = 0
while i < recipients.length
email.addTo recipients[i]
i++
substitutions = {
"%%name%%": [
"name1",
"name2"
],
"%%surname%%": [
"surname1",
"surname2"
]
}
for tag in substitutions
email.addSubstitution(tag, substitutions[tag])
email.setFilters({
"templates": {
"settings": {
"enable": "1",
"template_id": "XXXXXX-XXX-XXXX-XXXX-XXXXXXXXXX"
}
}
})
sendgrid.send email, (err, json) ->
if err
return console.log(err)
console.log json
return
When I execute the code send my the email to the emails address. But the message is:
Hello!!
%%name%% %%surname%% send you a message.
The substitution doesn't work. I try changing %% for %,- and #. But any ot those seems to work. Also I try using setSections.
Update
This is the sendgrid object i am sending.
{ to: [ 'example1#example.com', 'example2#example.com' ],
from: 'noreply#example.co',
smtpapi:
{ version: '1.2.0',
header:
{ to: [],
sub: {},
unique_args: {},
category: [Object],
section: {},
filters: [Object],
send_at: '',
send_each_at: [],
asm_group_id: {},
ip_pool: '' } },
subject: 'This Is The Subject',
text: 'Hello!\n\nThis is a test message from SendGrid. We have sent this to you because you requested a test message be sent from your account.\n\n This is a link to google.com: http://www.google.com\n This is a link to apple.com: http://www.apple.com\n This is a link to sendgrid.com: http://www.sendgrid.com\n\n Thank you for reading this test message.\n\nLove,\nYour friends at SendGrid',
html: '<table style="font-family: verdana, tahoma, sans-serif; color: #000;"> <tr> <td> <h2>Hello,</h2> <p>Hello!!</p> <p>%%name%% %%surname%% send you a message</p> </table>',
bcc: [],
cc: [],
replyto: '',
date: '',
headers: {},
toname: undefined,
fromname: undefined,
files: [] }
What am I doing wrong?
Thank you in advance.
I answer my own question because already found the problem.
The problem was not related with Sendgrid but with coffeeScript. In one of my statement I use this:
for tag in substitutions
email.addSubstitution(tag, substitutions[tag])
I try here to add to the email object the substitutions tag. But the debuging my code I found that the loop was not iterating over the substitution variable. So any tag was added to the email object.
I've changed the previous code for this one:
Object.keys(substitutions).forEach((tag)->
email.addSubstitution(tag, sub[tag])
return
And with this change the substitutions tags was added to the email object.

Resources