Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

API Simplification #378

Closed
wants to merge 3 commits into from
Closed

API Simplification #378

wants to merge 3 commits into from

Conversation

adamreisnz
Copy link
Contributor

@adamreisnz adamreisnz commented Apr 4, 2017

Mail service for the Sendgrid API

This is a dedicated service for interaction with the mail endpoint of the Sendgrid API.

Basic usage

Initialization with API key

Load the library and set the API key if you haven’t set it before:

//Load library
const sgMail = require('@sendgrid/mail');

//Set API key
sgMail.setApiKey(process.env.SENDGRID_API_KEY);

Single email to one recipient

Load the library, prepare your email data and use the send method:

//Load library
const sgMail = require('@sendgrid/mail');

//Create email data
const data = {
  to: 'recipient@example.org',
  from: 'sender@example.org',
  subject: 'Hello world',
  text: 'Hello plain world!',
  html: '<p>Hello HTML world!</p>',
};

//Send email
sgMail.send(data);

Single email to multiple recipients

The to field can contain an array of recipients, which will send a single email with all of the recipients in the to field. The recipients will be able to see each other:

//Load library
const sgMail = require('@sendgrid/mail');

//Create email data
const data = {
  to: ['recipient1@example.org', 'recipient2@example.org'],
  from: 'sender@example.org',
  subject: 'Hello world',
  text: 'Hello plain world!',
  html: '<p>Hello HTML world!</p>',
};

//Send email
sgMail.send(data);

Multiple emails to multiple recipients

If you want to send multiple individual emails to multiple recipient where they don't see each others email addresses, use sendMultiple instead:

//Load library
const sgMail = require('@sendgrid/mail');

//Create email data
const data = {
  to: ['recipient1@example.org', 'recipient2@example.org'],
  from: 'sender@example.org',
  subject: 'Hello world',
  text: 'Hello plain world!',
  html: '<p>Hello HTML world!</p>',
};

//Send emails
sgMail.sendMultiple(data);

Note that sendMultiple(data) is a convenience shortcut for send(data, true).

Multiple single emails

The send method also accepts an array of email data if you want to send multiple different single emails with for example different content and sender values. This will send multiple requests (in parallel), so be aware of any API rate restrictions:

//Load library
const sgMail = require('@sendgrid/mail');

//Create emails data
const emails = [
  {
    to: 'recipient1@example.org',
    from: 'sender@example.org',
    subject: 'Hello recipient 1',
    text: 'Hello plain world!',
    html: '<p>Hello HTML world!</p>',
  },
  {
    to: 'recipient2@example.org',
    from: 'other-sender@example.org',
    subject: 'Hello recipient 2',
    text: 'Hello other plain world!',
    html: '<p>Hello other HTML world!</p>',
  },
];

//Send emails
sgMail.send(emails);

Flexible email address fields

The email address fields (to, from, cc, bcc, replyTo) are flexible and can be any of the following:

const data = {

  //Simple email address string
  to: 'someone@example.org',

  //Email address with name
  to: 'Some One <someone@example.org>',

  //Object with name/email
  to: {
    name: 'Some One',
    email: 'someone@example.org',
  },
};

Handling success/failure

The send and sendMultiple methods return a Promise, so you can handle success and capture errors:

sgMail
  .send(data)
  .then(() => {
    //Celebrate
  })
  .catch(error => {
    //Do something with the error
  });

Alternatively, pass a callback function as the last parameter:

sgMail
  .send(data, (error, result) => {
    if (error) {
      //Do something with the error
    }
    else {
      //Celebrate
    }
  });

Advanced usage

All other advanced settings are supported and can be passed in through the data object according to the expected format as per the API v3 documentation. Note that you can use either camelCase or snake_case for property names.

Using transactional templates

Configure the substitution tag wrappers:

sgMail.setSubstitutionWrappers('{{', '}}');

Then provide a template ID and substitutions:

const data = {
  templateId: 'sendgrid-template-id',
  substitutions: {
    name: 'Some One',
    id: '123',
  },
};

Customization per recipient

To send multiple individual emails to multiple recipients with a different subject and/or substitutions, expand the to array as follows:

const data = {
  to: [
    {
      email: 'recipient1@example.org',
      subject: 'Hello recipient 1',
      substitutions: {
        name: 'Recipient 1',
        id: '123',
      },
    },
    {
      email: 'recipient2@example.org',
      subject: 'Hello recipient 2',
      substitutions: {
        name: 'Recipient 2',
        id: '456',
      },
    }
  ],
  from: 'sender@example.org',
  text: 'Hello plain world!',
  html: '<p>Hello HTML world!</p>',
};

Sending attachments

Attachments can be sent by providing an array of attachments as per the API specifications:

const data = {
  to: 'recipient@example.org',
  from: 'sender@example.org',
  subject: 'Hello attachment',
  html: '<p>Here’s an attachment for you!</p>',
  attachments: [
    {
      content: 'Some attachment content',
      filename: 'some-attachment.txt',
    },
  ],
};

Manually providing personalizations

Instead of using the to shorthand proper, you can still manually provide personalizations as per the API definition:

const data = {
  from: 'sender@example.org',
  text: 'Hello plain world!',
  html: '<p>Hello HTML world!</p>',
  personalizations: [
    {
      to: [
        {
          name: 'Someone',
          email: 'someone@example.org',
        },
      ],
      cc: [
        {
          name: 'Someone Else',
          email: 'someone.else@example.org',
        },
      ],
      subject: 'Some subject',
    }
  ],
};

Manually providing content

Instead of using the text and html shorthand properties, you can manually use the content property:

const data = {
  to: 'recipient@example.org',
  from: 'sender@example.org',
  subject: 'Hello manual content',
  content: [
    {
      type: 'text/html',
      value: '<p>Hello HTML world!</p>',
    },
    {
      type: 'text/plain',
      value: 'Hello plain world!',
    },
  ],
};

Specifying time to send at

Use the sendAt property to specify when to send the emails (in seconds, not milliseconds):

const data = {
  to: 'recipient@example.org',
  from: 'sender@example.org',
  subject: 'Hello delayed email',
  html: '<p>Some email content</p>',
  sendAt: 1500077141,
};

Specifying custom headers

Use the headers property to specify any custom headers:

const data = {
  to: 'recipient@example.org',
  from: 'sender@example.org',
  subject: 'Hello custom header',
  html: '<p>Some email content</p>',
  headers: {
    'X-CustomHeader': 'Custom header value',
  },
};

Specifying categories

Use the categories property to provide an array of categories for your email:

const data = {
  to: 'recipient@example.org',
  from: 'sender@example.org',
  subject: 'Hello email with categories',
  html: '<p>Some email content</p>',
  categories: [
    'transactional', 'customer', 'weekly',
  ],
};

Other options

All other options from the API definition are supported:

const data = {

  //Sections
  sections: {},

  //Custom arguments
  customArgs: {},

  //Batch ID
  batchId: String,

  //ASM
  asm: {},

  //IP pool name
  ipPoolName: String,

  //Mail settings
  mailSettings: {},

  //Tracking settings
  trackingSettings: {},
}

@SendGridDX SendGridDX added the status: code review request requesting a community code review or review from Twilio label Apr 4, 2017
@SendGridDX
Copy link
Collaborator

SendGridDX commented Apr 4, 2017

CLA assistant check
All committers have signed the CLA.

@adamreisnz
Copy link
Contributor Author

adamreisnz commented Apr 4, 2017

@thinkingserious I've created the above proposal for the 4 use cases required. Mostly this is adapted from my sendgrid-mailer library, as it seemed to be convenient and sensible and the community had favourable thoughts about it.

Additional observations:

  • The sendgrid.mail namespace represents that you are accessing methods in the Mail endpoint of the API. This will allow us to develop additional namespaces for the library to cover other endpoints as well, and to write convenience helper methods for those in due time.
  • I want to keep the helper classes, but refactor them slightly and make them easier to access and use. The above helper functions will use these helper classes internally to properly construct the underlying JSON payload and exposing them to the users will allow for more flexibility if needed.
  • All underlying "raw" methods will be made available as well, so you could still send completely custom JSON requests to the API endpoint.
  • As there will be some breaking changes this will likely be a new major release with significant refactoring.

I've already signed the CLA, but my Github username changed a while ago, so that might need to be updated in your system (used to be adambuczynski).

Let me know your thoughts and how you'd like to open this up for review by the community. Keen to start working on it once it's been approved.

@SendGridDX
Copy link
Collaborator

Hello @adamreisnz!

I am in agreement with your design.

I believe those interested in this redesign should follow along here. If it becomes difficult to communicate, we can explore other options.

I have alerted people that may be interested in this re-design.

@SendGridDX
Copy link
Collaborator

SendGridDX commented Apr 4, 2017

@adamreisnz,

With regards to the CLA, we rolled out a new, greatly simplified process. All you need to do now is fill out a short form and click a button. Please do that here. Thanks!

@thebigredgeek
Copy link

Would be great if this was ironed out quickly. I know several startups here in Silicon Valley who have moved away from sendgrid because of the new API design :(. We are also thinking about it

@SendGridDX
Copy link
Collaborator

Thanks for the feedback @thebigredgeek.

Do you have any thoughts on the new Mail Helper?

@thebigredgeek
Copy link

The API looks simple to use. The question, to me, is how long we will need to wait to start using it. The new V3 "API" has been very painful for us over the past few months, and has cost us countless man hours trying to debug bizarre sendgrid issues that we never had to deal with before.

@SendGridDX
Copy link
Collaborator

@thebigredgeek,

Thanks for the additional feedback!

Right now there are too many variables for me to give an accurate release date.

This particular issue, is at a high priority and we will do all we can to support @adamreisnz to get this ready for a stable release.

With regards to your current issues, please feel free to reach out to our team directly (dx@sendgrid.com) or here on GitHub, we are happy to help.

Also, it would be great to know the particular pain points you ran into so that we don't duplicate them with this next iteration.

@thebigredgeek
Copy link

thebigredgeek commented Apr 4, 2017

@SendGridDX Great! Sounds like you guys will hopefully ship soon. The issues with the old V3 "API" were caused by the horrendous design... "phase 1" or not... which required the gluing together of tens to hundreds of custom objects in order to send a single email. #335. It seems as though whoever was managing the transition to the V3 API didn't have much experience managing open source projects, as the V3 API shouldn't have even shipped if it wasn't finished and the legacy version should have been retained as the "production" lib until that time... Otherwise, you are literally screwing over the thousands of developers who are using this library to send email... along with your paying customers who are employing said developers. I am all for a better API, but you shouldn't roll out unfinished code to NPM as the "latest stable version". That's a very poor management decision in my opinion, since it probably cost you guys thousands of dollars in monthly revenue.

@SendGridDX
Copy link
Collaborator

Thank you @thebigredgeek once again for the valuable feedback. We will continue to make iterative improvements based on feedback such as yours, including how we handle releases. So thanks again for taking the time to express your issues.

In the meantime, we are here to help with any pain you are experiencing right now.

@adamreisnz
Copy link
Contributor Author

@thebigredgeek I'm happy to start working on it soon and get this out quickly. In the mean time, to alleviate your trouble, you can look into using https://www.npmjs.com/package/sendgrid-mailer. It's a wrapper I wrote to simplify the sending of emails with Sendgrid. My proposed API up here is pretty much an adaptation of the API in that package, so moving from it to the new version of the official package shouldn't be very time consuming.

Please let me know if you have any additional feedback on the API or additions you'd like to see to make sending emails for your use cases easier.

@thebigredgeek
Copy link

Thanks @adamreisnz . I hope you aren't doing this for free haha.

@transitive-bullshit
Copy link

Looks awesome! nodemailer support?

@adamreisnz
Copy link
Contributor Author

@fisch0920 I might look into that after the new API is there, but the priority at this stage is to release a new and easy to use API

@adamreisnz
Copy link
Contributor Author

@SendGridDX do you want to await more feedback or shall we get going with this?

@SendGridDX
Copy link
Collaborator

@adamreisnz,

I think we should get going.

Based on the feedback here and other feedback on other issues on your sendgrid-mailer package, I think you have laid out a solid path forward.

Thanks!

@adamreisnz
Copy link
Contributor Author

adamreisnz commented Apr 6, 2017

@SendGridDX Ok I'll get started. One thing though, I noticed you also added TS support, but I don't want to make my hands dirty with that, as I find that pleasing the TS community is often hard, usually filled with issues, and never very rewarding ;) Can I leave that for you or someone else on the team to implement once done? I say we focus on the pure JS implementation first, as the majority of Node users will still be using and favour ES over TS.

Also, what are the requirements in terms of backward support for various Node versions?
Are you ok with a new major release targeting modern Node versions so that we can leverage ES6/7 features, e.g. Node 6 and up?

@SendGridDX
Copy link
Collaborator

@spartan563,

Thoughts on helping us support TS as we update the Mail Helper?

@adamreisnz,

We need to support non End-of-Life versions: https://github.com/nodejs/LTS

@adamreisnz
Copy link
Contributor Author

@SendGridDX Hmm, Node 4 LTS has just entered maintenance phase, so I reckon we can focus on Node 6+ for this new development. Anyone on Node 4 can keep using the existing library and they are probably unlikely to switch to a new major version with a new API anyway. Thoughts?

@notheotherben
Copy link
Contributor

Hey guys, more than happy to help out - just ping me when you're nearing completion and I'll slot it into my schedule somewhere. If you have a time-box, let me know and I'll try to prioritise to meet that.

@SendGridDX
Copy link
Collaborator

Hi @adamreisnz,

I not too familiar with what it means to enter maintenance phase. Is there a dramatic drop off in usage when this happens?

And yes, that's true, we can point people to this version of the SDK if they are stuck on Node 4.

@adamreisnz
Copy link
Contributor Author

Well it means there's still one year of maintenance support of that Node version, but this mostly pertains critical security fixes.

Once a release moves into Maintenance mode, only critical bugs, critical security fixes, and documentation updates will be permitted.

So personally I don't think at this stage it's necessary to keep offering support for Node 4 with the new API.

@SendGridDX
Copy link
Collaborator

Does anyone else following this thread have an opinion on supporting (or not) Node.js 4?

@thebigredgeek
Copy link

I think v4+ is ideal. Most people don't use old versions of node in production

@adamreisnz
Copy link
Contributor Author

@thinkingserious I have now also deprecated https://www.npmjs.com/package/sendgrid-mailer so if that's still on the list of 3rd party packages feel free to remove it as it won't be needed anymore.

@thinkingserious
Copy link
Contributor

Thanks for the heads up, I've put in a PR to do so: sendgrid/docs#2788

@adamreisnz
Copy link
Contributor Author

Quick update, I've improved a couple of things regarding recipient handling and error response handling, as well as updated the readme with some additional examples and use cases.

There's a few things still not 100% around the handling of cc/bcc's. I'm working on fixing that now and adding some tests for the helper classes to make sure they convert to the proper JSON.

@ameesme
Copy link

ameesme commented Jul 21, 2017

Just implemented 6.0.0-beta.3 and it works beautifully, for at least basic transactional emails:).

@adamreisnz
Copy link
Contributor Author

Awesome, please update to beta 4 for some fixes around cc/bcc handling!

@johndatserakis
Copy link

johndatserakis commented Jul 23, 2017

Been following this thread for a while now. Thank you @adamreisnz, @thinkingserious, and others for their work on this.

Very excited to use the new progress - but I'm having a strange issue installing the package. Just to warn - there's a very good chance I'm just being incredibly dull.

When I go to npm install @sendgrid/mail I get this error:

404 Not Found: @sendgrid/mail-helpers@^6.0.0-beta.0

And I get a little bit more of an error when manually adding it to my package.json and npm install 'ing from there:

No matching version found for @sendgrid/helpers@^6.0.0
In most cases you or one of your dependencies are requesting a package version that doesn't exist.
It was specified as a dependency of '@sendgrid/client'

I've also tried this: npm install git://github.com/sendgrid/sendgrid-nodejs.git#v6.0.0-beta.3 which seemed to install, but then I can't require @sendgrid/mail in my code (or other variants like sendgrid), as it says module not found.

Perhaps it's just a small tweak I need when installing? Thank you.

@adamreisnz
Copy link
Contributor Author

@johndatserakis indeed it is. The first version published for this package had the beta suffix, and npm doesn't seem to handle that well when running just npm install @sendgrid/mail. You can fix it by explicitly specifying the latest version:

npm install @sendgrid/mail@6.0.0-beta.4

or

yarn add @sendgrid/mail@6.0.0-beta.4

If/when prompted, also choose the beta 4 version for the helpers package.

It should work as expected again once the "full" version is released.

@johndatserakis
Copy link

Awesome thanks @adamreisnz - when using yarn the option to choose the helper version came up fine - although it didn't offer any such option in npm. It's nice that yarn does that, hopefully npm will adopt that (it might already and I'm just doing it wrong). Although as you mentioned in the future it won't be needed. Thanks again.

@adamreisnz
Copy link
Contributor Author

adamreisnz commented Jul 23, 2017 via email

@adamreisnz
Copy link
Contributor Author

How's everyone that has tested the new API doing with it? Encountered any issues? Have any additional suggestions?

@johndatserakis
Copy link

johndatserakis commented Aug 2, 2017

Working well in my usage.

import sgMail from '@sendgrid/mail';
sgMail.setApiKey(process.env.SENDGRID_API_KEY);
...

let email = await fse.readFile('./src/email/welcome.html', 'utf8');
const emailData = {
  to: ctx.request.body.email,
  from: process.env.APP_EMAIL,
  subject: 'Welcome To Koa-Vue-Notes-Api',
  html: email,
  categories: ['koa-vue-notes-api-new-user'],
  substitutions: {
    appName: process.env.APP_NAME,
    appEmail: process.env.APP_EMAIL,
  },
};

//Initial function call has the async flag. Works great.
await sgMail.send(emailData);

I'm loading an html email template using fs-extra, making substitutions, and adding a category. All good - although I noticed I couldn't use a $ sign in my potential substitution target in my html. No biggie though - just a simple pivot.

Great work. I also really like how simple constructing and sending an email was.

@thinkingserious
Copy link
Contributor

Thanks for taking the time to provide feedback @johndatserakis!

@adamreisnz
Copy link
Contributor Author

adamreisnz commented Aug 2, 2017

Thanks for the feedback!

@thinkingserious is the $ substitution issue related to Sendgrid's templating engine you think?

@thinkingserious
Copy link
Contributor

@adamreisnz,

I think so, I've seen similar issues in the past. Fortunately, it looks like that system is getting an overhaul shortly. Please bring up that issue when you chat with Matt :)

With Best Regards,

Elmer

@danteata
Copy link

danteata commented Aug 7, 2017

Hi @adamreisnz,
Any chance using this on a CI platform at the moment?

@adamreisnz
Copy link
Contributor Author

@danteata I think the dependency for one of the packages was invalid and manually set to ^6.0.0, which didn't match the current beta version, and Lerna didn't seem to have updated it.

@thinkingserious I have pushed a change and updated the version, could you release a new beta and check if the versions in all the packages are correct? Then the install should go without hiccups.

@thinkingserious
Copy link
Contributor

Thanks @adamreisnz! I should be able to dig in within the next few days. My apologies for the delay.

@haydenbleasel
Copy link

haydenbleasel commented Aug 12, 2017

Hey @adamreisnz, amazing work with this so far. Followed your initial instructions for Single email to one recipient with the following setup:

const data = {
    to: 'xxx@gmail.com',
    from: {
        email: 'xxx@gmail.com',
        name: 'xxx'
    },
    subject: 'hello',
    html: '<p>hi</p>',
    customArgs: {
        foo: 'bar'
    },
}

Sendgrid.send(data).then(() => {
    res.status(200).send({ success: true });
}).catch((error) => {
    res.status(500).send(error);
});

But it results in the following error:

Failed to send email Error: Object expected for `substitutions`
    at Personalization.reverseMergeSubstitutions (.../node_modules/@sendgrid/helpers/classes/personalization.js:251:13)

@sendgrid/mail 6.0.0-beta.4

@adamreisnz
Copy link
Contributor Author

Hi @haydenbleasel, thank you!

Yes, I fixed that bug but still waiting on @thinkingserious to release a new version. You can use beta.3 for now which doesn't have this bug.

@thinkingserious
Copy link
Contributor

My apologies for the delay @adamreisnz & @haydenbleasel. I will be posting here when I get the chance to update to the new version.

@adamreisnz
Copy link
Contributor Author

6.0.0-beta.5 has now been released, which has fixed the issue with npm/yarn complaining about invalid dependency. Thanks @thinkingserious !

@transitive-bullshit
Copy link

transitive-bullshit commented Aug 28, 2017

why doesn't the default @sendgrid/mail 404 and not point to the latest?

you should never have your users needing to follow a random github thread in order to figure out why your default package doesn't install properly.

also, when will the default docs be updated to point to this lib instead of the more verbose version? as it stands, this library which i'm guessing 95% of your node.js users will want is way too hidden.

@adamreisnz
Copy link
Contributor Author

adamreisnz commented Aug 28, 2017

@fisch0920 version 6 has not been released yet officially, as far as I know, so the beta version is the last currently available one, so you use it at your own risk. The annoying thing about npm is that it doesn't consider beta versions as stable versions, so if that's your initial version of a package, they won't install or cause some installation issues.

The default package should be the old version still, called sendgrid-nodejs.

Once this version gets released as 6.0.0 it will become the default. The docs for this version have already been improved and should be up to date.

@thinkingserious do you have a timeline for the release of 6.0.0?

@thinkingserious
Copy link
Contributor

@adamreisnz, @fisch0920,

I don't think it will take longer than early this week to officially launch v6.0.0. If you subscribe to this repo's release notes, you will get emailed when the release is official.

Thanks!

With Best Regards,

Elmer

@thinkingserious
Copy link
Contributor

Hello Everyone!

v6.0.0 has been officially released! Enjoy!

With Best Regards,

Elmer

@transitive-bullshit
Copy link

transitive-bullshit commented Aug 28, 2017

Thanks, everyone! This is a huge win for the Node Sendgrid community 👍

Awesome work, @adamreisnz @thinkingserious and everyone else who contributed.

Now onto sending emails...

@adamreisnz
Copy link
Contributor Author

Awesome thanks everyone for their feedback and contributions! 🎉

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
status: code review request requesting a community code review or review from Twilio status: work in progress Twilio or the community is in the process of implementing
Projects
None yet
Development

Successfully merging this pull request may close these issues.