Skip to content

Commit

Permalink
Merge pull request #53 from emailjs-com/sdk-v4
Browse files Browse the repository at this point in the history
SDK v4
  • Loading branch information
xr0master authored Feb 3, 2024
2 parents 4179e8d + c238f03 commit 5f21dde
Show file tree
Hide file tree
Showing 43 changed files with 1,489 additions and 227 deletions.
4 changes: 2 additions & 2 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -6,9 +6,9 @@ name: CI
on:
# Triggers the workflow on push or pull request events but only for the master branch
push:
branches: [ master ]
branches: [ master, sdk-v4 ]
pull_request:
branches: [ master ]
branches: [ master, sdk-v4 ]

# Allows you to run this workflow manually from the Actions tab
workflow_dispatch:
Expand Down
165 changes: 131 additions & 34 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,14 +2,15 @@

SDK for [EmailJS.com](https://www.emailjs.com) customers.
\
Use you EmailJS account for sending emails.
Use your EmailJS account for sending emails.

[![codecov](https://codecov.io/gh/emailjs-com/emailjs-sdk/branch/master/graph/badge.svg)](https://codecov.io/gh/emailjs-com/emailjs-sdk)
[![npm version](https://img.shields.io/npm/v/@emailjs/browser.svg)](https://www.npmjs.com/package/@emailjs/browser)

## Disclaimer

This is a browser-only version, otherwise use

- [Node.js SDK](https://www.npmjs.com/package/@emailjs/nodejs)
- [Flutter SDK](https://pub.dev/packages/emailjs)
- [REST API](https://www.emailjs.com/docs/rest-api/send/)
Expand All @@ -20,7 +21,7 @@ This is a browser-only version, otherwise use

## Intro

EmailJS helps to send emails using client-side technologies only.
EmailJS helps you send emails directly from code with one command.
No server is required – just connect EmailJS to one of the supported
email services, create an email template, and use our SDK
to trigger an email.
Expand All @@ -29,67 +30,163 @@ to trigger an email.

Install EmailJS SDK using [npm](https://www.npmjs.com/):

```bash
```bash
$ npm install @emailjs/browser
```

Or manually:

```html
```html
<script
type="text/javascript"
src="https://cdn.jsdelivr.net/npm/@emailjs/browser@3/dist/email.min.js">
src="https://cdn.jsdelivr.net/npm/@emailjs/browser@4/dist/email.min.js">
</script>
<script type="text/javascript">
(function () {
emailjs.init('<YOUR_PUBLIC_KEY>');
emailjs.init({
publicKey: 'YOUR_PUBLIC_KEY',
});
})();
</script>
```

## Examples

**send email**
**Send the email using the customized send method**

```js
```js
var templateParams = {
name: 'James',
notes: 'Check this out!'
name: 'James',
notes: 'Check this out!',
};

emailjs.send('<YOUR_SERVICE_ID>','<YOUR_TEMPLATE_ID>', templateParams)
.then(function(response) {
console.log('SUCCESS!', response.status, response.text);
}, function(err) {
console.log('FAILED...', err);
});
emailjs.send('YOUR_SERVICE_ID', 'YOUR_TEMPLATE_ID', templateParams).then(
function (response) {
console.log('SUCCESS!', response.status, response.text);
},
function (err) {
console.log('FAILED...', err);
},
);
```

**Send the email from a form using the sendForm method**

```js
emailjs.sendForm('YOUR_SERVICE_ID', 'YOUR_TEMPLATE_ID', '#myForm').then(
function (response) {
console.log('SUCCESS!', response.status, response.text);
},
function (err) {
console.log('FAILED...', err);
},
);
```

**send form**
**Using Angular / VueJS / ReactJS / Svelte / any other modern framework**

```js
import emailjs from '@emailjs/browser';

const templateParams = {
name: 'James',
notes: 'Check this out!',
};

emailjs
.send('YOUR_SERVICE_ID', 'YOUR_TEMPLATE_ID', templateParams, {
publicKey: 'YOUR_PUBLIC_KEY',
})
.then(
(response) => {
console.log('SUCCESS!', response.status, response.text);
},
(err) => {
console.log('FAILED...', err);
},
);
```

## Configuration

**Options**

Options can be declared globally using the **init** method or locally as the fourth parameter of a function.
\
The local parameter will have higher priority than the global one.

| Name | Type | Default | Description |
| ------------- | --------- | ------- | -------------------------------------------------------- |
| publicKey | String | | The public key is required to invoke the method. |
| blockHeadless | Boolean | False | Method will return error 451 if the browser is headless. |
| blockList | BlockList | | Block list settings. |
| limitRate | LimitRate | | Limit rate configuration. |

**BlockList**

Allows to ignore a method call if the watched variable contains a value from the block list.
\
The method will return the error 403 if the request is blocked.

| Name | Type | Description |
| ------------- | -------- | -------------------------------------------------- |
| list | String[] | The array of strings contains values for blocking. |
| watchVariable | String | A name of the variable to be watched. |

**LimitRate**

Allows to set the limit rate for calling a method.
\
If the request hits the limit rate, the method will return the error 429.

| Name | Type | Default | Description |
| -------- | ------ | --------- | ---------------------------------------------------------------------------------------------------------------------------------------- |
| id | String | page path | The limit rate is per page by default. To override the behavior, set the ID. It can be a custom ID for each page, group, or application. |
| throttle | Number | | _(ms)_ After how many milliseconds a next request is allowed. |

**Declare global settings**

```js
import emailjs from '@emailjs/browser';

```js
emailjs.sendForm('<YOUR_SERVICE_ID>','<YOUR_TEMPLATE_ID>', '#myForm')
.then(function(response) {
console.log('SUCCESS!', response.status, response.text);
}, function(err) {
console.log('FAILED...', err);
});
emailjs.init({
publicKey: 'YOUR_PUBLIC_KEY',
blockHeadless: true,
blockList: {
list: ['[email protected]', '[email protected]'],
},
limitRate: {
throttle: 10000, // 10s
},
});
```

**Angular X / VueJS / ReactJS**
**Overwrite settings locally**

```js
```js
import emailjs from '@emailjs/browser';

const templateParams = {
name: 'James',
notes: 'Check this out!'
name: 'James',
notes: 'Check this out!',
};

emailjs.send('<YOUR_SERVICE_ID>','<YOUR_TEMPLATE_ID>', templateParams, '<YOUR_PUBLIC_KEY>')
.then((response) => {
console.log('SUCCESS!', response.status, response.text);
}, (err) => {
console.log('FAILED...', err);
});
emailjs
.send('YOUR_SERVICE_ID', 'YOUR_TEMPLATE_ID', templateParams, {
publicKey: 'YOUR_PUBLIC_KEY',
blockList: {
watchVariable: 'userEmail',
},
limitRate: {
throttle: 0, // turn off the limit rate for these requests
},
})
.then(
(response) => {
console.log('SUCCESS!', response.status, response.text);
},
(err) => {
console.log('FAILED...', err);
},
);
```
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@
"build:lint": "eslint src --ext ts,tsx --report-unused-disable-directives --max-warnings 0",
"build:bundle": "webpack --env production",
"build": "npm run build:clean && npm run build:lint && npm run build:ts && npm run build:cjs && npm run build:bundle",
"test": "jest --coverage",
"test": "jest --coverage --no-cache",
"lint": "tsc --noEmit && eslint src"
},
"keywords": [
Expand Down
35 changes: 12 additions & 23 deletions src/api/sendPost.ts
Original file line number Diff line number Diff line change
@@ -1,34 +1,23 @@
import { EmailJSResponseStatus } from '../models/EmailJSResponseStatus';
import { store } from '../store/store';

export const sendPost = (
export const sendPost = async (
url: string,
data: string | FormData,
headers: Record<string, string> = {},
): Promise<EmailJSResponseStatus> => {
return new Promise((resolve, reject) => {
const xhr = new XMLHttpRequest();

xhr.addEventListener('load', ({ target }) => {
const responseStatus = new EmailJSResponseStatus(target as XMLHttpRequest);

if (responseStatus.status === 200 || responseStatus.text === 'OK') {
resolve(responseStatus);
} else {
reject(responseStatus);
}
});

xhr.addEventListener('error', ({ target }) => {
reject(new EmailJSResponseStatus(target as XMLHttpRequest));
});
const response = await fetch(store.origin + url, {
method: 'POST',
headers,
body: data,
});

xhr.open('POST', store._origin + url, true);
const message = await response.text();
const responseStatus = new EmailJSResponseStatus(response.status, message);

Object.keys(headers).forEach((key) => {
xhr.setRequestHeader(key, headers[key]);
});
if (response.ok) {
return responseStatus;
}

xhr.send(data);
});
throw responseStatus;
};
15 changes: 15 additions & 0 deletions src/errors/blockedEmailError/blockedEmailError.spec.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
import { it, expect } from '@jest/globals';

import { EmailJSResponseStatus } from '../../models/EmailJSResponseStatus';
import { blockedEmailError } from './blockedEmailError';

it('should return EmailJSResponseStatus', () => {
expect(blockedEmailError()).toBeInstanceOf(EmailJSResponseStatus);
});

it('should return status 403', () => {
expect(blockedEmailError()).toEqual({
status: 403,
text: 'Forbidden',
});
});
5 changes: 5 additions & 0 deletions src/errors/blockedEmailError/blockedEmailError.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
import { EmailJSResponseStatus } from '../../models/EmailJSResponseStatus';

export const blockedEmailError = () => {
return new EmailJSResponseStatus(403, 'Forbidden');
};
15 changes: 15 additions & 0 deletions src/errors/headlessError/headlessError.spec.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
import { it, expect } from '@jest/globals';

import { EmailJSResponseStatus } from '../../models/EmailJSResponseStatus';
import { headlessError } from './headlessError';

it('should return EmailJSResponseStatus', () => {
expect(headlessError()).toBeInstanceOf(EmailJSResponseStatus);
});

it('should return status 451', () => {
expect(headlessError()).toEqual({
status: 451,
text: 'Unavailable For Headless Browser',
});
});
5 changes: 5 additions & 0 deletions src/errors/headlessError/headlessError.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
import { EmailJSResponseStatus } from '../../models/EmailJSResponseStatus';

export const headlessError = () => {
return new EmailJSResponseStatus(451, 'Unavailable For Headless Browser');
};
15 changes: 15 additions & 0 deletions src/errors/limitRateError/limitRateError.spec.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
import { it, expect } from '@jest/globals';

import { EmailJSResponseStatus } from '../../models/EmailJSResponseStatus';
import { limitRateError } from './limitRateError';

it('should return EmailJSResponseStatus', () => {
expect(limitRateError()).toBeInstanceOf(EmailJSResponseStatus);
});

it('should return status 451', () => {
expect(limitRateError()).toEqual({
status: 429,
text: 'Too Many Requests',
});
});
5 changes: 5 additions & 0 deletions src/errors/limitRateError/limitRateError.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
import { EmailJSResponseStatus } from '../../models/EmailJSResponseStatus';

export const limitRateError = () => {
return new EmailJSResponseStatus(429, 'Too Many Requests');
};
Loading

0 comments on commit 5f21dde

Please sign in to comment.