I am having issue in sending mails to multiple recipients.
My script is
var SendGrid = require('sendgrid').SendGrid;
var sendgrid = new SendGrid('<<username>>', '<<password>>');
sendgrid.send({
to: 'nabababa#gmail.com',
from: 'sengupta.nabarun#gmail.com',
bcc: ["sengupta.nabarun#gmail.com","sengupta_nabarun#rediffmail.com"],
I have two questions here
Can I have an array of recipients in to list?
How can I get an array of recipients in bcc list?
Solutions related to above two queries will be indeed helpful
Thanks
Nabarun
You may use an array of recipients in both the to and bcc fields.
For example:
var SendGrid = require('sendgrid').SendGrid;
var sendgrid = new SendGrid('{{sendgrid username}}', '{{sendgrid password}}');
sendgrid.send({
to: ['one#example.com', 'two#example.com'],
from: 'nick#sendgrid.com',
bcc: ['three#example.com', 'four#example.com'],
subject: 'This is a demonstration of SendGrid sending email to mulitple recipients.',
html: '<img src="http://3.bp.blogspot.com/-P6jNF5dU_UI/TTgpp3K4vSI/AAAAAAAAD2I/V4JC33e6sPM/s1600/happy2.jpg" style="width: 100%" />'
});
If this isn't working for you and Node isn't spitting out any errors, check to see if the emails are being sent, by logging into SendGrid's website and looking at the Email Activity Log.
One thing I came across while testing your code sample is if you're sending the to and bcc to the same gmail address, gmail will combine it all into one email (so it appears it didn't work). Make sure when testing you're sending email to entirely different accounts.
If you need some email accounts to test with Guerrilla Mail is an excellent option for creating temporary test accounts.
This is the solution that I ended up with and thought it was more straightforward and could be helpful for folks.
Note the difference in the shape of the personalizations object.
Recipients can see each other:
const sgMail = require('#sendgrid/mail')
sgMail.setApiKey(process.env.SENDGRID_API_KEY)
// Declare the content we'll use for the email
const FROM_EMAIL = 'example#example.io' // <-- Replace with your email
const subject = 'Test Email Subject'
const body = '<p>Hello HTML world!</p>'
const recipients = ['alice#example.com', 'bob#example.com'] // <-- Add your email(s) here to test
// Create the personalizations object that will be passed to our message object
let personalizations = [{
to: [],
subject
}]
// Iterate over our recipients and add them to the personalizations object
for (let index in recipients) {
personalizations[0].to[index] = { email: recipients[index] }
}
const msg = {
personalizations,
from: FROM_EMAIL,
html: body,
}
// Log to see what our message object looks like
console.log(msg)
// Send the email, if success log it, else log the error message
sgMail.send(msg)
.then(() => console.log('Mail sent successfully'))
.catch(error => console.error(error.toString()))
Personalizations Object:
{
personalizations: [{
to: [
{email: "alice#example.com"},
{email: "bob#example.com"},
],
subject: "Test Email Subject"
}]
}
Recipients can not see each other:
// Create the personalizations object that will be passed to our message object
personalizations = []
// Iterate over our recipients and add them to the personalizations object
for (let index in recipients) {
personalizations[index] = { to: recipients[index], subject}
}
Personalizations Object:
{
personalizations: [
{
to: "alice#example.com",
subject: "Test Email Subject"
},
{
to: "bob#example.com",
subject: "Test Email Subject"
}
]
}
I created a RunKit with the full solution and where you can test it out.
For Sendgrid's v3 API, I found their "kitchen sink" example helpful. Here is a relevant bit from it:
var helper = require('sendgrid').mail
mail = new helper.Mail()
email = new helper.Email("test#example.com", "Example User")
mail.setFrom(email)
mail.setSubject("Hello World from the SendGrid Node.js Library")
personalization = new helper.Personalization()
email = new helper.Email("test1#example.com", "Example User")
personalization.addTo(email)
email = new helper.Email("test2#example.com", "Example User")
personalization.addTo(email)
// ...
mail.addPersonalization(personalization)
The new sendgrid-nodejs update has scrapped previous implementation methods and therefore the accepted answer wont help you now.
So... just an update in case anyone lands to this thread with specific search result.
to: [
{
email: 'email1#email.com',
},
{
email: 'email2#email.com',
},
],
A solution for TypeScript (written in ts version 3.4.3 and sendGrid 7.1.1) where you don't want recipients to be able to see each other.
import * as sendGrid from '#sendgrid/mail'
type UserEmail = {
to: string
subject: string
}
// Add as many recipients as you want
recipients = ['email1#global.com', 'email2#gmail.com']
const personalizations: UserEmail[] = recipients.map(admin => ({
to: admin,
subject: 'Inject Subject Here',
}))
try {
await sendGrid.send({
from, // Inject
personalizations,
html, // Inject
})
} catch (err) {
console.log(err)
}
const personalizations looks like this
[{ to: 'email1#global.com',
subject: 'Inject Subject Here' },
{ to: 'email2#global.com',
subject: 'Inject Subject Here' }]
Related
I am having a nodejs code trigerring sendgrid email to 1000+ users. When the number users is less (100-200)this works fine. But when there are 1000+ users it fails at a point and the rest of the mails are not triggered. When i check the app service it is shown as SNAT port exhaustion.
userList.forEach(async(Element) => {
console.log(Element.userId);
let textContentUser="";
let emailContentUser="";
textContentUser=textContent;
var userData=await db.collection('masterUserDetails').find({"userId":Element.userId}).toArray();
if(userData.length>0)
{
textContentUser=textContentUser.split("{{FirstName}}").join(userData[0]["givenName"]);
textContentUser=textContentUser.split("{{FullName}}").join(userData[0]["preferredName"]);
var leadReviewerData=await db.collection('masterUserDetails').find({"userId":userData[0]["counselorEmail"]}).toArray();
if(leadReviewerData.length==0)
{
textContentUser=textContentUser.split("{{LeadReviewerFullName}}").join(userData[0]["counselorName"]);
textContentUser=textContentUser.split("{{LeadReviewerFirstName}}").join(userData[0]["counselorName"]);
}
else
{
textContentUser=textContentUser.split("{{LeadReviewerFullName}}").join(leadReviewerData[0]["preferredName"]);
textContentUser=textContentUser.split("{{LeadReviewerFirstName}}").join(leadReviewerData[0]["givenName"]);
}
}
console.log("final Text cintent: ",textContentUser);
emailContentUser=emailContent;
emailContentUser=emailContentUser.replace("***content***",textContentUser);
//console.log("final email cintent: ",emailContentUser);
const msg = {
to: Element.userId, // Change to your recipient
bcc:"support_test#abc.com",
from: {
"email": "support#abc.com",
"name": "MY APP"
}, // Change to your verified sender
subject: emailSubject,
html: emailContentUser,
attachments: [
{
filename:"image002.gif",
content: img2,
content_id:"image002",
disposition:"inline"
},
{
filename:"image004.gif",
content: img4,
content_id:"image004",
disposition:"inline"
}],
reply_to: {
"email": "support.test#abc.com",
"name": "My APP Support"
},
send_at: sendAt
}
console.log("sending mail")
sgMail
.send(msg)
.then((response) => {
console.log("Success--------"+response[0].statusCode)
//console.log(response[0].headers)
})
.catch((error) => {
// console.log("error");
console.log("Error--------"+JSON.stringify(error))
})
});
This works in local. works when deployed in azure with lesser users also.
As others have noted, you're running out of SNAT ports to make the HTTP request to the SendGrid API.
I would recommend avoiding making an HTTP request for every email you want to send and instead use the built-in APIs to send multiple emails using one HTTP request.
To do so, add a personalizations property to your msg with an array. Add objects to the array to override the msg properties for that specific personalization, properties like subject, from, to, etc. as documented here. You can add a max of 1000 items to the personalizations array. So if you want to send more than 1000 emails, you'll need to create a separate msg for every 1000 emails, but now you only send a single HTTP request for every 1000 emails, so you shouldn't run into SNAT port errors as quickly.
Now, if you're using a single email body template but want to personalize the email, you can use Substitution Tags in your template and add a substitutions property to your personalization objects with an object holding the data you want to substitute.
Note: The total collective size of your substitutions may not exceed 10,000 bytes per personalization object.
The default substitution wrapper is "{{" and "}}" for the node.js library. Here's an example how using one msg, you can send multiple emails using personalizations and substitutions:
const sgMail = require('#sendgrid/mail');
sgMail.setApiKey(process.env.SENDGRID_API_KEY);
const recipients = [
{
emailAddress: "recipient1#email.address",
preferredName: "Jonny",
counselorName: "Smith"
},
{
emailAddress: "recipient2#email.address",
preferredName: "Jay",
counselorName: "Smith"
}
];
const msg = {
// this will create an array of objects with `to` and `substitutions ` properties
personalizations: recipients.map(r => {
return {
to: r.emailAddress,
substitutions: {
preferredName: r.preferredName,
counselorName: r.counselorName
}
}
}),
from: 'your#sendgrid.sender',
subject: 'Ahoy!',
html: `<p>Ahoy {{preferredName}}!</p>
<p>It is a pleasure to meet you.</p>
<p>Best, {{counselorName}}</p>`
};
sgMail.send(msg).then(() => {
console.log('emails sent successfully!');
}).catch(error => {
console.log(error);
});
Pay attention to the html template containing substitution tags like {{preferredName}} and {{counselorName}}. These tag names have to match with the keys of the object in the substitutions property.
Warning: Substitution tags will not automatically HTML encode user input, so you have to HTML encode it yourself to prevent HTML injection attacks. You can learn more about HTML injection attacks here.
If you don't need to store the email body template in your code, you can use Dynamic Email Template as shown in this sample. You can create Dynamic Email Templates in the SendGrid app and use handlebar templating to add template data into your emails.
Updating the previous example with Dynamic Email Templates would look like this:
const msg = {
// this will create an array of objects with `to` and `dynamicTemplateData` properties
personalizations: recipients.map(r => {
return {
to: r.emailAddress,
dynamicTemplateData: {
preferredName: r.preferredName,
counselorName: r.counselorName
}
}
}),
from: 'your#sendgrid.sender',
templateId: 'd-[REPLACE_WITH_YOUR_TEMPLATE_ID]'
};
sgMail.send(msg).then(() => {
console.log('emails sent successfully!');
}).catch(error => {
console.log(error);
});
The subject and substitutions properties have been removed. The templateId and dynamicTemplateData have been added.
Note: Dynamic Email Templates use handlebar templating which will HTML encode user input, protecting you from HTML injection.
Last suggestion: Twilio recommends schedule your bulk emails by using the sendAt property instead of sending them right now.
Quoting from the SendGrid docs:
This technique allows for a more efficient way to distribute large
email requests and can improve overall mail delivery time performance.
This functionality:
Improves efficiency of processing and distributing large volumes of email.
Reduces email pre-processing time.
Enables you to time email arrival to increase open rates.
Is available for free to all SendGrid customers.
I am using Docusign SDK for NodeJS and below is sample code that I followed from nodejs github example.
let taxYear = docusign.Text.constructFromObject({
customTabId:"taxYear",
tabLabel: "taxYear",
value:"2018"
})
let signer1Tabs = docusign.Tabs.constructFromObject({
textTabs: [taxYear]
})
// Create a signer recipient for the signer role of the server template
let signer1 = docusign.Signer.constructFromObject({
email: args.signerEmail,
name: args.signerName,
roleName: "signer",
recipientId: "1",
// Adding clientUserId transforms the template recipient
// into an embedded recipient:
clientUserId: "1",
tabs: signer1Tabs
});
// Create the cc recipient
let cc1 = docusign.CarbonCopy.constructFromObject({
email: args.ccEmail,
name: args.ccName,
roleName: "cc",
recipientId: "2"
});
// Recipients object:
let recipientsServerTemplate = docusign.Recipients.constructFromObject({
carbonCopies: [cc1], signers: [signer1], });
// create a composite template for the Server Template
let compTemplate1 = docusign.CompositeTemplate.constructFromObject({
compositeTemplateId: "1",
serverTemplates: [
docusign.ServerTemplate.constructFromObject({
sequence: "1",
templateId: args.templateId
})
],
// Add the roles via an inlineTemplate
inlineTemplates: [
docusign.InlineTemplate.constructFromObject({
sequence: "1",
recipients: recipientsServerTemplate
})
]
})
// create the envelope definition
let env = docusign.EnvelopeDefinition.constructFromObject({
status: "sent",
compositeTemplates: [compTemplate1]
})
return env;
I have custom text field with tab label as taxYear but I am not seeing it getting posted in the form when envelop is sent out.
Here is the out put I am receiving
Not sure what I am missing!!!!!!
The Taxfield that you're using does not appear to have an X/Y location or anchor string attached to it -- so our system would not know where to place it.
For these fields to be added, you need to supply the documentId (if using x/y coordinates), recipientId, tabLabel, and either the x/y position or an anchor string to place it.
If adding those doesn't seem to do it, please edit your comment with the parameters specifically for the taxYear tab and we can have another look at it.
I have a script which is working OK to send emails, but I have a requirement to attach the email to:
Multiple Entities (incl Projects)
Support Case
Multiple Custom records (mail merge is active)
My current script is as follows:
var emaildata = {body: field.fld_message+'<br />'+attachmentList+signature,
author: sender.entityid,
recipients: primary.email,
subject: field.fld_subject,
cc : cc_entities,
bcc : bcc_entities,
relatedRecords: {
entityId: entities,
activityId: field.claimid,
}
};
sendemail.send(emaildata);
The array variable entities contains the employees/partners I want to attach the email too, but it is not attaching to the records.
For the custom records, i have tried including this in the email data object:
customRecord: [
{id: field.submitid, recordType: 267},
{id: field.scopeid, recordType: 73 },
{id: field.assessid, recordType: 83 },
],
But sadly it is not working...
What am I doing wrong?
The email is being sent (sometimes) but not attaching.
When i tried with just ONE custom record, but was getting an Unexpected Suitescript error:
customRecord: {id: field.submitid, recordType: 267 }
I have confirmed the "id" fields are populated corrected.
var records = new Array();
records['record'] = '11'; // internal id of the record
records['recordtype'] = '250'; // record type id
nlapiSendEmail ( from,to,subject,body,cc,bcc,records,files);
It is working.`enter code here`
Note: I'm using the 'classic' experience because the new interface doesn't have a way for a template to set up required fields for future signers.
The workflow:
have a template with a bunch of fields
using the api:
create an envelope/document from the template, and assign a new user to sign (this document is going to be an agreement for signing up for a service)
create new role
set roleName to fake signer on template (because I can't configure fields without at least one signer on the template)
add textTabs to try to perfill some of the fields.
retrieve the recipients
create a recipient view so that I get the URL to put in an iframe
This is kind of obnoxious, because I don't care about having a first signer that isn't the user signing up for the service. I would however, like to have the the document be copied to someone after signing, but docusign doesn't appear to support this (that I've found anyway).
Here is the node.js code for the creation of the envelope (where I think my API usage is going wrong):
function createEnvelopeDefinition(templateId, userData) {
var envDef = new docusign.EnvelopeDefinition();
envDef.setEmailSubject('Signup Agreement');
envDef.setTemplateId(templateId);
var tRole = new docusign.TemplateRole();
tRole.setRoleName('RoleOne');
tRole.setName(userData.fullName);
tRole.setEmail(userData.email);
tRole.setClientUserId('2');
tRole.setTabs(new docusign.Tabs());
tRole.getTabs().setTextTabs([]);
const fieldsToPreFill = [
'field1',
'field2',
'field3',
'field4'];
fieldsToPreFill.forEach(fieldName => {
let textTab = new docusign.Text();
let value = userData[fieldName];
if (value === null || value === undefined) { value = 'not null'; }
textTab.setTabLabel(fieldName);
textTab.setValue(value);
tRole.getTabs().getTextTabs().push(textTab);
});
tRole = removeNulls(tRole);
envDef.setTemplateRoles([tRole]);
// send the envelope by setting |status| to 'sent'.
// To save as a draft set to 'created'
// sent is required for getting view URLs
envDef.setStatus('sent');
return envDef;
}
In the template editor on docusign, the Data Field Tag Properties show the label of each of the corresponding fields as field1, field2, etc.
These fields are now filled out with the provided values when I throw the new envelope in an iframe.
just for reference here is the rest of the code that creates the api connection, and gets the view URL
import ENV from 'environment/backend';
const accountId = ENV.docusign.accountId;
var Promise = require('bluebird');
var docusign = require('docusign-esign');
export function newApiClient() {
let apiClient = new docusign.ApiClient();
apiClient.setBasePath(ENV.docusign.endpoint);
// create JSON formatted auth header
let creds = JSON.stringify({
Username: ENV.docusign.email,
Password: ENV.docusign.password,
IntegratorKey: ENV.docusign.integratorKey
});
apiClient.addDefaultHeader('X-DocuSign-Authentication', creds);
// assign api client to the Configuration object
// this probably doesn't need to be set every time...
docusign.Configuration.default.setDefaultApiClient(apiClient);
return apiClient;
}
const defaultApiClient = newApiClient();
const envelopesApi = new docusign.EnvelopesApi();
const createEnvelope = Promise.promisify(envelopesApi.createEnvelope, { context: envelopesApi });
const listRecipients = Promise.promisify(envelopesApi.listRecipients, { context: envelopesApi });
const createRecipientView = Promise.promisify(envelopesApi.createRecipientView, { context: envelopesApi });
export default defaultApiClient;
// promise resolves to the view URL, envelopeId for the user.
// returns a recipientView
export function setupDocumentForEmbeddedSigning(templateId, userData) {
let envDefinition = createEnvelopeDefinition(templateId, userData);
return createEnvelope(accountId, envDefinition, null)
.then(envelopeSummary => {
const envelopeId = envelopeSummary.envelopeId;
return createViewFromEnvelope(envelopeId);
});
}
export function createViewFromEnvelope(envelopeId) {
return getRecipients(envelopeId).then(recipients => {
// the last signer is the one we added in the
// createEnvelopeDefinition step
let signers = recipients.signers;
let lastSigner = signers[signers.length - 1];
return createView(envelopeId, lastSigner)
.then(recipientView => [recipientView.url, envelopeId]);
});
}
function getRecipients(envelopeId) {
return listRecipients(accountId, envelopeId);
}
function createView(envelopeId, signerData) {
var viewRequest = new docusign.RecipientViewRequest();
viewRequest.setReturnUrl(ENV.host);
viewRequest.setAuthenticationMethod('email');
// recipient information must match embedded recipient info
// from the createEnvelopeDefinition method
viewRequest.setEmail(signerData.email);
viewRequest.setUserName(signerData.name);
viewRequest.setRecipientId('2');
viewRequest.setClientUserId('2');
return createRecipientView(accountId, envelopeId, viewRequest);
}
// bug with the api wrapper
// https://github.com/docusign/docusign-node-client/issues/47
const removeNulls = function(obj) {
var isArray = obj instanceof Array;
for (var k in obj) {
if (obj[k] === null) isArray ? obj.splice(k, 1) : delete obj[k];
else if (typeof obj[k] == 'object') removeNulls(obj[k]);
if (isArray && obj.length == k) removeNulls(obj);
}
return obj;
};
So, I may not fully understand where you're stuck, but I'll take a crack at this anyway...
Let's say I create a Template using the DocuSign UI and define two Recipient roles:
Signer1 (which will be the person who is signing up for your service) -- Action = "Sign"
CarbonCopy1 (which will be the person who gets a copy of the completed/signed documents once Signer1 signs) -- Action = "Receive a Copy"
(Note: these roles can be named whatever you want to name them -- I named them "Signer1" and "CarbonCopy1" so it'd be clear who each role represents.)
Assuming the above scenario, your Template's Recipient Roles (in the DocuSign UI) will look like this:
Next, let's assume that you define some fields (tabs) in the Template's document(s) (i.e., using the DocuSign UI) that the Signer1 recipient will need to populate when they sign the document(s). For this example, let's assume that the label (name) of one of those Text tabs is field1. Notice that the field is assigned to the Signer1 recipient:
Now, if I want to create an Envelope via the API that uses this Template, and pre-fill fields for one or more of the recipients, the key to doing that is using the "Composite Templates" structure in the API request. (See the Composite Templates section of this page for details.) In the example described above, your compositeTemplates object in the API request would contain a single serverTemplate object (which specifies the templateId and sequence=1), and a single inlineTemplate object (which specifies sequence=2 and the recipient info, including values for any tabs (fields) that you want to pre-fill).
In the example described above, the JSON API request to create the Envelope would look like this (assuming we're just pre-filling a single field for Signer1 -- obviously you could pre-fill additional fields by simply including them in the tabs object of the request along with field1):
POST https://{{env}}.docusign.net/restapi//v2/accounts/{{accountId}}/envelopes
{
"emailSubject": "Test Pre-fill Tabs",
"emailBlurb": "This is a test.",
"compositeTemplates": [{
"serverTemplates": [{
"sequence": "1",
"templateId": "CD0E6D53-3447-4A9E-BBAF-0EB2C78E8310"
}],
"inlineTemplates":[{
"sequence": "2",
"recipients": {
"signers": [
{
"roleName": "Signer1",
"recipientId": "1",
"name": "John Doe",
"email": "johndoe#test.com",
"clientUserId": "1234",
"tabs": {
"textTabs": [
{
"tabLabel": "field1",
"value": "TEST-123"
}
]
}
},
{
"roleName": "CarbonCopy1",
"recipientId": "2",
"name": "Jane Doe",
"email": "janedoe#test.com"
}
]
}
}]
}],
"status": "sent"
}
Once I create the Envelope using the above request, I execute a "POST Recipient View" request to get the signing URL for the first recipient (https://{{env}}.docusign.net/restapi//v2/accounts/{{accountId}}/envelopes/{{envelopeId/views/recipient).
Then, when I subsequently use the URL that's returned in that response to launch the signing session for Signer1 (John Doe), I see that the field1 tab is indeed pre-filled with the value that I specified in the "Create Envelope" API request (TEST-123):
Furthermore, once John Doe (Signer1) finishes signing and submits the completed documents, Jane Doe (CarbonCopy1) will be sent a copy.
I'm not familiar with the DocuSign Node SDK, but imagine you can figure out the syntax to use composite templates as shown in the above example. Hope this helps!
I'm trying to yet up a subscription using Stripe checkout.js and then using PHP to Subscribe customers. My problem is getting their email address. Can't find anything useful in the docs.
Docs here: https://stripe.com/docs/guides/subscriptions#step-2-subscribe-customers
What I have:
<script src="https://checkout.stripe.com/checkout.js"></script>
<button id="customButton">Purchase</button>
<script>
var handler = StripeCheckout.configure({
key: 'pk_test_keyhere',
image: '/square-image.png',
token: function(token) {
// Use the token to create the charge with a server-side script.
// You can access the token ID with `token.id`
}
});
document.getElementById('customButton').addEventListener('click', function(e) {
// Open Checkout with further options
handler.open({
name: 'test2',
description: 'Test Des',
amount: 0001,
currency:'GBP'
});
e.preventDefault();
});
</script>
<?php
// Set your API key
Stripe::setApiKey("sk_test_keyhere");
$token = $_POST['stripeToken'];
$customer = Stripe_Customer::create(array(
"card" => $token,
"plan" => "test2",
"email" => $email
)
);
?>
Adding to David's answer, you can retrieve the email address via PHP like so:
$stripeinfo =Stripe_Token::retrieve($_POST["token"]);
echo '<pre>',print_r($stripeinfo),'</pre>'; //show stripeObject info
$email = $stripeinfo->email;
Adding a small update to this answer for people who are coming across this now.
$token = $_POST['stripeToken'];
$stripeinfo = \Stripe\Token::retrieve($token);
$email = $stripeinfo->email;
$customer = \Stripe\Customer::create(array(
'email' => $email,
'source' => $token,
'description' => 'New Customer'
));
Just some small changes I had to make to get my code to work.
If you are using Checkout you will be passed a token, using that token you can obtain the email address through an API call: https://stripe.com/docs/api#retrieve_token
Not sure why email isn't listed under there but I do have an email attribute available to me. You can also see the email under the Stripe's logs.