diff --git a/backend/.env b/backend/.env index 952b683..db99f2f 100644 --- a/backend/.env +++ b/backend/.env @@ -8,5 +8,6 @@ EMAIL_HOST= EMAIL_PORT= EMAIL_USER= EMAIL_PASS= +SENDGRID_SENDER_NAME= SENDGRID_API_KEY= EMAIL_FROM= \ No newline at end of file diff --git a/backend/controller/authController.js b/backend/controller/authController.js index 63b1ea8..eae1cdc 100644 --- a/backend/controller/authController.js +++ b/backend/controller/authController.js @@ -3,6 +3,8 @@ const argon2 = require('argon2'); const randomstring = require('randomstring'); const {User} = require('../models'); // Pastikan sesuai dengan struktur project require('dotenv').config(); +const nodemailer = require('nodemailer'); +const sgMail = require('@sendgrid/mail'); // Fungsi untuk membuat token JWT const generateToken = (user) => { @@ -78,30 +80,198 @@ exports.login = async (req, res) => { } }; -exports.forgotPassword = async (req, res) => { +// Buat transporter Nodemailer dengan Gmail +const createGmailTransporter = () => { + return nodemailer.createTransport({ + service: 'gmail', + auth: { + user: process.env.EMAIL_FROM, // sibayam52@gmail.com dari .env yang sudah ada + pass: process.env.EMAIL_PASS, // Gunakan App Password, bukan password biasa! + }, + // Pool koneksi untuk menghindari rate limiting + pool: true, + maxConnections: 3, + maxMessages: 50, + rateDelta: 1500, + rateLimit: 3 + }); + }; + + exports.sendResetCodeWithGmail = async (req, res) => { + const { email } = req.body; + try { - const { email, password } = req.body; // Gunakan 'password' sebagai field yang dikirim - - // 🔹 Validasi input - if (!email || !password) { - return res.status(400).json({ message: "Email dan password baru harus diisi" }); - } - - // 🔹 Cek apakah user dengan email tersebut ada - const user = await User.findOne({ where: { email } }); - if (!user) { - return res.status(404).json({ message: "User tidak ditemukan" }); - } - - // 🔹 Hash password baru dengan Argon2 - const hashedPassword = await argon2.hash(password); - - // 🔹 Update password user di database - await user.update({ password: hashedPassword }); - - res.status(200).json({ message: "Password berhasil diperbarui" }); + // Validasi email + if (!email || !email.includes('@')) { + return res.status(400).json({ message: 'Email tidak valid' }); + } + + const user = await User.findOne({ where: { email } }); + if (!user) return res.status(404).json({ message: 'User tidak ditemukan' }); + + // Generate 6 digit random code + const code = Math.floor(100000 + Math.random() * 900000).toString(); + const expiresAt = new Date(Date.now() + 10 * 60 * 1000); + + await user.update({ + resetToken: code, + resetTokenExpiry: expiresAt, + }); + + // Nama aplikasi yang konsisten + const appName = process.env.SENDGRID_SENDER_NAME || 'SistemPakar SIBAYAM'; + + // Coba buat transporter setiap kali untuk menghindari koneksi mati + const transporter = createGmailTransporter(); + + // Email sangat sederhana tetapi efektif + const mailOptions = { + from: `"${appName}" <${process.env.EMAIL_FROM}>`, // Menggunakan EMAIL_FROM dari .env + to: email, + subject: `[${code}] Kode Verifikasi ${appName}`, // Tanda kode di subject membantu visibilitas + html: ` +
Halo ${user.name || 'Pengguna'},
+Anda telah meminta untuk mereset password akun SIBAYAM Anda.
+Kode verifikasi Anda:
+Kode ini akan kadaluarsa dalam 10 menit.
+Jika Anda tidak meminta reset password, abaikan email ini.
+Email ini dikirim oleh sistem SIBAYAM. Mohon jangan membalas email ini.
+Halo ${user.name || 'Pengguna'},
+Password akun SIBAYAM Anda telah berhasil diubah.
+✓ Password telah diperbarui
+Jika Anda tidak melakukan perubahan ini, segera hubungi tim dukungan kami.
+Email ini dikirim oleh sistem SIBAYAM. Mohon jangan membalas email ini.
+Check out our spring line!
", + "ip_pool": "marketing", + "list_ids": [ + 110, + 124 + ], + "plain_content": "Check out our spring line!", + "segment_ids": [ + 110 + ], + "sender_id": 124451, + "subject": "New Products for Spring!", + "suppression_group_id": 42, + "title": "March Newsletter" +}; + request.body = data; + request.method = 'POST'; + request.url = '/v3/campaigns'; + client.request(request) + .then(([response, body]) => { + console.log(response.statusCode); + console.log(response.body); + }) +``` +## Retrieve all Campaigns + +**This endpoint allows you to retrieve a list of all of your campaigns.** + +Returns campaigns in reverse order they were created (newest first). + +Returns an empty array if no campaigns exist. + +For more information: + +* [User Guide > Marketing Campaigns](https://sendgrid.com/docs/User_Guide/Marketing_Campaigns/index.html) + +### GET /campaigns + + +```javascript + const queryParams = { + 'limit': 1, + 'offset': 1 +}; + request.qs = queryParams; + request.method = 'GET'; + request.url = '/v3/campaigns'; + client.request(request) + .then(([response, body]) => { + console.log(response.statusCode); + console.log(response.body); + }) +``` +## Update a Campaign + +Update a campaign. This is especially useful if you only set up the campaign using POST /campaigns, but didn't set many of the parameters. + +For more information: + +* [User Guide > Marketing Campaigns](https://sendgrid.com/docs/User_Guide/Marketing_Campaigns/index.html) + +### PATCH /campaigns/{campaign_id} + + +```javascript + const data = { + "categories": [ + "summer line" + ], + "html_content": "Check out our summer line!
", + "plain_content": "Check out our summer line!", + "subject": "New Products for Summer!", + "title": "May Newsletter" +}; + request.body = data; + request.method = 'PATCH'; + request.url = '/v3/campaigns/{campaign_id}'; + client.request(request) + .then(([response, body]) => { + console.log(response.statusCode); + console.log(response.body); + }) +``` +## Delete a Campaign + +**This endpoint allows you to delete a specific campaign.** + +Our Marketing Campaigns API lets you create, manage, send, and schedule campaigns. + +For more information: + +* [User Guide > Marketing Campaigns](https://sendgrid.com/docs/User_Guide/Marketing_Campaigns/index.html) + +### DELETE /campaigns/{campaign_id} + + +```javascript + request.method = 'DELETE'; + request.url = '/v3/campaigns/{campaign_id}'; + client.request(request) + .then(([response, body]) => { + console.log(response.statusCode); + console.log(response.body); + }) +``` +## Retrieve a single campaign + +**This endpoint allows you to retrieve a specific campaign.** + +Our Marketing Campaigns API lets you create, manage, send, and schedule campaigns. + +For more information: + +* [User Guide > Marketing Campaigns](https://sendgrid.com/docs/User_Guide/Marketing_Campaigns/index.html) + +### GET /campaigns/{campaign_id} + + +```javascript + request.method = 'GET'; + request.url = '/v3/campaigns/{campaign_id}'; + client.request(request) + .then(([response, body]) => { + console.log(response.statusCode); + console.log(response.body); + }) +``` +## Unschedule a Scheduled Campaign + +**This endpoint allows you to unschedule a campaign that has already been scheduled to be sent.** + +A successful unschedule will return a 204. +If the specified campaign is in the process of being sent, the only option is to cancel (a different method). + +For more information: + +* [User Guide > Marketing Campaigns](https://sendgrid.com/docs/User_Guide/Marketing_Campaigns/index.html) + +### DELETE /campaigns/{campaign_id}/schedules + + +```javascript + request.method = 'DELETE'; + request.url = '/v3/campaigns/{campaign_id}/schedules'; + client.request(request) + .then(([response, body]) => { + console.log(response.statusCode); + console.log(response.body); + }) +``` +## Schedule a Campaign + +**This endpoint allows you to schedule a specific date and time for your campaign to be sent.** + +For more information: + +* [User Guide > Marketing Campaigns](https://sendgrid.com/docs/User_Guide/Marketing_Campaigns/index.html) + +### POST /campaigns/{campaign_id}/schedules + + +```javascript + const data = { + "send_at": 1489771528 +}; + request.body = data; + request.method = 'POST'; + request.url = '/v3/campaigns/{campaign_id}/schedules'; + client.request(request) + .then(([response, body]) => { + console.log(response.statusCode); + console.log(response.body); + }) +``` +## View Scheduled Time of a Campaign + +**This endpoint allows you to retrieve the date and time that the given campaign has been scheduled to be sent.** + +For more information: + +* [User Guide > Marketing Campaigns](https://sendgrid.com/docs/User_Guide/Marketing_Campaigns/index.html) + +### GET /campaigns/{campaign_id}/schedules + + +```javascript + request.method = 'GET'; + request.url = '/v3/campaigns/{campaign_id}/schedules'; + client.request(request) + .then(([response, body]) => { + console.log(response.statusCode); + console.log(response.body); + }) +``` +## Update a Scheduled Campaign + +**This endpoint allows to you change the scheduled time and date for a campaign to be sent.** + +For more information: + +* [User Guide > Marketing Campaigns](https://sendgrid.com/docs/User_Guide/Marketing_Campaigns/index.html) + +### PATCH /campaigns/{campaign_id}/schedules + + +```javascript + const data = { + "send_at": 1489451436 +}; + request.body = data; + request.method = 'PATCH'; + request.url = '/v3/campaigns/{campaign_id}/schedules'; + client.request(request) + .then(([response, body]) => { + console.log(response.statusCode); + console.log(response.body); + }) +``` +## Send a Campaign + +**This endpoint allows you to immediately send a campaign at the time you make the API call.** + +Usually, a POST would have a request body, but since this endpoint is telling us to send a resource that is already created, a request body is not needed. + +For more information: + +* [User Guide > Marketing Campaigns](https://sendgrid.com/docs/User_Guide/Marketing_Campaigns/index.html) + +### POST /campaigns/{campaign_id}/schedules/now + + +```javascript + request.method = 'POST'; + request.url = '/v3/campaigns/{campaign_id}/schedules/now'; + client.request(request) + .then(([response, body]) => { + console.log(response.statusCode); + console.log(response.body); + }) +``` +## Send a Test Campaign + +**This endpoint allows you to send a test campaign.** + +To send to multiple addresses, use an array for the JSON "to" value ["one@address","two@address"] + +For more information: + +* [User Guide > Marketing Campaigns](https://sendgrid.com/docs/User_Guide/Marketing_Campaigns/index.html) + +### POST /campaigns/{campaign_id}/schedules/test + + +```javascript + const data = { + "to": "your.email@example.com" +}; + request.body = data; + request.method = 'POST'; + request.url = '/v3/campaigns/{campaign_id}/schedules/test'; + client.request(request) + .then(([response, body]) => { + console.log(response.statusCode); + console.log(response.body); + }) +``` + +# CATEGORIES + +## Retrieve all categories + +**This endpoint allows you to retrieve a list of all of your categories.** + +Categories can help organize your email analytics by enabling you to tag emails by type or broad topic. You can define your custom categories. For more information, please see our [User Guide](https://sendgrid.com/docs/User_Guide/Statistics/categories.html). + +### GET /categories + + +```javascript + const queryParams = { + 'category': 'test_string', + 'limit': 1, + 'offset': 1 +}; + request.qs = queryParams; + request.method = 'GET'; + request.url = '/v3/categories'; + client.request(request) + .then(([response, body]) => { + console.log(response.statusCode); + console.log(response.body); + }) +``` +## Retrieve Email Statistics for Categories + +**This endpoint allows you to retrieve all of your email statistics for each of your categories.** + +If you do not define any query parameters, this endpoint will return a sum for each category in groups of 10. + +Categories allow you to group your emails according to broad topics that you define. For more information, please see our [User Guide](https://sendgrid.com/docs/User_Guide/Statistics/categories.html). + +### GET /categories/stats + + +```javascript +const queryParams = { + 'aggregated_by': 'day', + 'categories': 'test_string', + 'end_date': '2016-04-01', + 'limit': 1, + 'offset': 1, + 'start_date': '2016-01-01' +}; +request.qs = queryParams; +request.method = 'GET'; +request.url = '/v3/categories/stats'; +client + .request(request) + .then(([response, body]) => { + console.log(response.statusCode); + console.log(response.body); + }) +``` + + +**Attention:** in order to receive the email statistics for multiple categories at once, you need to set the `qsStringifyOptions` as follows: + +```javascript +const client = require('@sendgrid/client') +client.setDefaultRequest('qsStringifyOptions', {arrayFormat: 'repeat'}); + +const request = {} +const queryParams = { + 'aggregated_by': 'day', + 'categories': ['test_category_1', 'cat facts'], + 'end_date': '2016-04-01', + 'limit': 1, + 'offset': 1, + 'start_date': '2016-01-01' +}; +request.qs = queryParams; +request.method = 'GET'; +request.url = '/v3/categories/stats'; +client + .request(request) + .then(([response, body]) => { + console.log(response.statusCode); + console.log(response.body); + }) +``` +## Retrieve sums of email stats for each category [Needs: Stats object defined, has category ID?] + +**This endpoint allows you to retrieve the total sum of each email statistic for every category over the given date range.** + +If you do not define any query parameters, this endpoint will return a sum for each category in groups of 10. + +Categories allow you to group your emails according to broad topics that you define. For more information, please see our [User Guide](https://sendgrid.com/docs/User_Guide/Statistics/categories.html). + +### GET /categories/stats/sums + + +```javascript + const queryParams = { + 'aggregated_by': 'day', + 'end_date': '2016-04-01', + 'limit': 1, + 'offset': 1, + 'sort_by_direction': 'asc', + 'sort_by_metric': 'test_string', + 'start_date': '2016-01-01' +}; + request.qs = queryParams; + request.method = 'GET'; + request.url = '/v3/categories/stats/sums'; + client.request(request) + .then(([response, body]) => { + console.log(response.statusCode); + console.log(response.body); + }) +``` + +# CLIENTS + +## Retrieve email statistics by client type. + +**This endpoint allows you to retrieve your email statistics segmented by client type.** + +**We only store up to 7 days of email activity in our database.** By default, 500 items will be returned per request via the Advanced Stats API endpoints. + +Advanced Stats provide a more in-depth view of your email statistics and the actions taken by your recipients. You can segment these statistics by geographic location, device type, client type, browser, and mailbox provider. For more information about statistics, please see our [User Guide](https://sendgrid.com/docs/User_Guide/Statistics/index.html). + +### GET /clients/stats + + +```javascript + const queryParams = { + 'aggregated_by': 'day', + 'end_date': '2016-04-01', + 'start_date': '2016-01-01' +}; + request.qs = queryParams; + request.method = 'GET'; + request.url = '/v3/clients/stats'; + client.request(request) + .then(([response, body]) => { + console.log(response.statusCode); + console.log(response.body); + }) +``` +## Retrieve stats by a specific client type. + +**This endpoint allows you to retrieve your email statistics segmented by a specific client type.** + +**We only store up to 7 days of email activity in our database.** By default, 500 items will be returned per request via the Advanced Stats API endpoints. + +## Available Client Types +- phone +- tablet +- webmail +- desktop + +Advanced Stats provide a more in-depth view of your email statistics and the actions taken by your recipients. You can segment these statistics by geographic location, device type, client type, browser, and mailbox provider. For more information about statistics, please see our [User Guide](https://sendgrid.com/docs/User_Guide/Statistics/index.html). + +### GET /clients/{client_type}/stats + + +```javascript + const queryParams = { + 'aggregated_by': 'day', + 'end_date': '2016-04-01', + 'start_date': '2016-01-01' +}; + request.qs = queryParams; + request.method = 'GET'; + request.url = '/v3/clients/{client_type}/stats'; + client.request(request) + .then(([response, body]) => { + console.log(response.statusCode); + console.log(response.body); + }) +``` + +# CONTACTDB + +## Create a Custom Field + +**This endpoint allows you to create a custom field.** + +The contactdb is a database of your contacts for [Twilio SendGrid Marketing Campaigns](https://sendgrid.com/docs/User_Guide/Marketing_Campaigns/index.html). + +### POST /contactdb/custom_fields + + +```javascript + const data = { + "name": "pet", + "type": "text" +}; + request.body = data; + request.method = 'POST'; + request.url = '/v3/contactdb/custom_fields'; + client.request(request) + .then(([response, body]) => { + console.log(response.statusCode); + console.log(response.body); + }) +``` +## Retrieve all custom fields + +**This endpoint allows you to retrieve all custom fields.** + +The contactdb is a database of your contacts for [Twilio SendGrid Marketing Campaigns](https://sendgrid.com/docs/User_Guide/Marketing_Campaigns/index.html). + +### GET /contactdb/custom_fields + + +```javascript + request.method = 'GET'; + request.url = '/v3/contactdb/custom_fields'; + client.request(request) + .then(([response, body]) => { + console.log(response.statusCode); + console.log(response.body); + }) +``` +## Delete a Custom Field + +**This endpoint allows you to delete a custom field by ID.** + +The contactdb is a database of your contacts for [Twilio SendGrid Marketing Campaigns](https://sendgrid.com/docs/User_Guide/Marketing_Campaigns/index.html). + +### DELETE /contactdb/custom_fields/{custom_field_id} + + +```javascript + request.method = 'DELETE'; + request.url = '/v3/contactdb/custom_fields/{custom_field_id}'; + client.request(request) + .then(([response, body]) => { + console.log(response.statusCode); + console.log(response.body); + }) +``` +## Retrieve a Custom Field + +**This endpoint allows you to retrieve a custom field by ID.** + +The contactdb is a database of your contacts for [Twilio SendGrid Marketing Campaigns](https://sendgrid.com/docs/User_Guide/Marketing_Campaigns/index.html). + +### GET /contactdb/custom_fields/{custom_field_id} + + +```javascript + request.method = 'GET'; + request.url = '/v3/contactdb/custom_fields/{custom_field_id}'; + client.request(request) + .then(([response, body]) => { + console.log(response.statusCode); + console.log(response.body); + }) +``` +## Create a List + +**This endpoint allows you to create a list for your recipients.** + +The Contacts API helps you manage your [Marketing Campaigns](https://sendgrid.com/docs/User_Guide/Marketing_Campaigns/index.html) recipients. + +### POST /contactdb/lists + + +```javascript + const data = { + "name": "your list name" +}; + request.body = data; + request.method = 'POST'; + request.url = '/v3/contactdb/lists'; + client.request(request) + .then(([response, body]) => { + console.log(response.statusCode); + console.log(response.body); + }) +``` +## Delete Multiple lists + +**This endpoint allows you to delete multiple recipient lists.** + +The Contacts API helps you manage your [Marketing Campaigns](https://sendgrid.com/docs/User_Guide/Marketing_Campaigns/index.html) recipients. + +### DELETE /contactdb/lists + + +```javascript + const data = [ + 1, + 2, + 3, + 4 +]; + request.body = data; + request.method = 'DELETE'; + request.url = '/v3/contactdb/lists'; + client.request(request) + .then(([response, body]) => { + console.log(response.statusCode); + console.log(response.body); + }) +``` +## Retrieve all lists + +**This endpoint allows you to retrieve all of your recipient lists. If you don't have any lists, an empty array will be returned.** + +The Contacts API helps you manage your [Marketing Campaigns](https://sendgrid.com/docs/User_Guide/Marketing_Campaigns/index.html) recipients. + +### GET /contactdb/lists + + +```javascript + request.method = 'GET'; + request.url = '/v3/contactdb/lists'; + client.request(request) + .then(([response, body]) => { + console.log(response.statusCode); + console.log(response.body); + }) +``` +## Delete a List + +**This endpoint allows you to delete a specific recipient list with the given ID.** + +The Contacts API helps you manage your [Marketing Campaigns](https://sendgrid.com/docs/User_Guide/Marketing_Campaigns/index.html) recipients. + +### DELETE /contactdb/lists/{list_id} + + +```javascript + const queryParams = { + 'delete_contacts': 'true' +}; + request.qs = queryParams; + request.method = 'DELETE'; + request.url = '/v3/contactdb/lists/{list_id}'; + client.request(request) + .then(([response, body]) => { + console.log(response.statusCode); + console.log(response.body); + }) +``` +## Update a List + +**This endpoint allows you to update the name of one of your recipient lists.** + + +The Contacts API helps you manage your [Marketing Campaigns](https://sendgrid.com/docs/User_Guide/Marketing_Campaigns/index.html) recipients. + +### PATCH /contactdb/lists/{list_id} + + +```javascript + const data = { + "name": "newlistname" +}; + request.body = data; + const queryParams = { + 'list_id': 1 +}; + request.qs = queryParams; + request.method = 'PATCH'; + request.url = '/v3/contactdb/lists/{list_id}'; + client.request(request) + .then(([response, body]) => { + console.log(response.statusCode); + console.log(response.body); + }) +``` +## Retrieve a single list + +This endpoint allows you to retrieve a single recipient list. + +The Contacts API helps you manage your [Marketing Campaigns](https://sendgrid.com/docs/User_Guide/Marketing_Campaigns/index.html) recipients. + +### GET /contactdb/lists/{list_id} + + +```javascript + const queryParams = { + 'list_id': 1 +}; + request.qs = queryParams; + request.method = 'GET'; + request.url = '/v3/contactdb/lists/{list_id}'; + client.request(request) + .then(([response, body]) => { + console.log(response.statusCode); + console.log(response.body); + }) +``` +## Add Multiple Recipients to a List + +**This endpoint allows you to add multiple recipients to a list.** + +Adds existing recipients to a list, passing in the recipient IDs to add. Recipient IDs should be passed exactly as they are returned from recipient endpoints. + +The Contacts API helps you manage your [Marketing Campaigns](https://sendgrid.com/docs/User_Guide/Marketing_Campaigns/index.html) recipients. + +### POST /contactdb/lists/{list_id}/recipients + + +```javascript + const data = [ + "recipient_id1", + "recipient_id2" +]; + request.body = data; + request.method = 'POST'; + request.url = '/v3/contactdb/lists/{list_id}/recipients'; + client.request(request) + .then(([response, body]) => { + console.log(response.statusCode); + console.log(response.body); + }) +``` +## Retrieve all recipients on a List + +**This endpoint allows you to retrieve all recipients on the list with the given ID.** + +The Contacts API helps you manage your [Marketing Campaigns](https://sendgrid.com/docs/User_Guide/Marketing_Campaigns/index.html) recipients. + +### GET /contactdb/lists/{list_id}/recipients + + +```javascript +const queryParams = { + 'page': 1, + 'page_size': 1 +}; +request.qs = queryParams; +request.method = 'GET'; +var list_id = 1; +request.url = '/v3/contactdb/lists/{list_id}/recipients'; +client.request(request) +.then(([response, body]) => { + console.log(response.statusCode); + console.log(response.body); +}) +``` +## Add a Single Recipient to a List + +**This endpoint allows you to add a single recipient to a list.** + +The Contacts API helps you manage your [Marketing Campaigns](https://sendgrid.com/docs/User_Guide/Marketing_Campaigns/index.html) recipients. + +### POST /contactdb/lists/{list_id}/recipients/{recipient_id} + + +```javascript + request.method = 'POST'; + request.url = '/v3/contactdb/lists/{list_id}/recipients/{recipient_id}'; + client.request(request) + .then(([response, body]) => { + console.log(response.statusCode); + console.log(response.body); + }) +``` +## Delete a Single Recipient from a Single List + +**This endpoint allows you to delete a single recipient from a list.** + +The Contacts API helps you manage your [Marketing Campaigns](https://sendgrid.com/docs/User_Guide/Marketing_Campaigns/index.html) recipients. + +### DELETE /contactdb/lists/{list_id}/recipients/{recipient_id} + + +```javascript + const queryParams = { + 'list_id': 1, + 'recipient_id': 1 +}; + request.qs = queryParams; + request.method = 'DELETE'; + request.url = '/v3/contactdb/lists/{list_id}/recipients/{recipient_id}'; + client.request(request) + .then(([response, body]) => { + console.log(response.statusCode); + console.log(response.body); + }) +``` +## Add recipients + +**This endpoint allows you to add a Marketing Campaigns recipient.** + +You can add custom field data as a parameter on this endpoint. We have provided an example using some of the default custom fields Twilio SendGrid provides. + +The Contacts API helps you manage your [Marketing Campaigns](https://sendgrid.com/docs/User_Guide/Marketing_Campaigns/index.html) recipients. + +### POST /contactdb/recipients + + +```javascript + const data = [ + { + "age": "25", + "email": "example@example.com", + "first_name": "", + "last_name": "User" + }, + { + "age": "25", + "email": "example2@example.com", + "first_name": "Example", + "last_name": "User" + } +]; + request.body = data; + request.method = 'POST'; + request.url = '/v3/contactdb/recipients'; + client.request(request) + .then(([response, body]) => { + console.log(response.statusCode); + console.log(response.body); + }) +``` +## Delete Recipient + +**This endpoint allows you to delete one or more recipients.** + +The body of an API call to this endpoint must include an array of recipient IDs of the recipients you want to delete. + +The contactdb is a database of your contacts for [Twilio SendGrid Marketing Campaigns](https://sendgrid.com/docs/User_Guide/Marketing_Campaigns/index.html). + +### DELETE /contactdb/recipients + + +```javascript + const data = [ + "recipient_id1", + "recipient_id2" +]; + request.body = data; + request.method = 'DELETE'; + request.url = '/v3/contactdb/recipients'; + client.request(request) + .then(([response, body]) => { + console.log(response.statusCode); + console.log(response.body); + }) +``` +## Retrieve recipients + +**This endpoint allows you to retrieve all of your Marketing Campaigns recipients.** + +Batch deletion of a page makes it possible to receive an empty page of recipients before reaching the end of +the list of recipients. To avoid this issue; iterate over pages until a 404 is retrieved. + +The Contacts API helps you manage your [Marketing Campaigns](https://sendgrid.com/docs/User_Guide/Marketing_Campaigns/index.html) recipients. + +### GET /contactdb/recipients + + +```javascript + const queryParams = { + 'page': 1, + 'page_size': 1 +}; + request.qs = queryParams; + request.method = 'GET'; + request.url = '/v3/contactdb/recipients'; + client.request(request) + .then(([response, body]) => { + console.log(response.statusCode); + console.log(response.body); + }) +``` +## Update Recipient + +**This endpoint allows you to update one or more recipients.** + +The body of an API call to this endpoint must include an array of one or more recipient objects. + +It is of note that you can add custom field data as parameters on recipient objects. We have provided an example using some of the default custom fields Twilio SendGrid provides. + +The contactdb is a database of your contacts for [Twilio SendGrid Marketing Campaigns](https://sendgrid.com/docs/User_Guide/Marketing_Campaigns/index.html). + +### PATCH /contactdb/recipients + + +```javascript + const data = [ + { + "email": "jones@example.com", + "first_name": "Guy", + "last_name": "Jones" + } +]; + request.body = data; + request.method = 'PATCH'; + request.url = '/v3/contactdb/recipients'; + client.request(request) + .then(([response, body]) => { + console.log(response.statusCode); + console.log(response.body); + }) +``` +## Retrieve the count of billable recipients + +**This endpoint allows you to retrieve the number of Marketing Campaigns recipients that you will be billed for.** + +You are billed for marketing campaigns based on the highest number of recipients you have had in your account at one time. This endpoint will allow you to know the current billable count value. + +The Contacts API helps you manage your [Marketing Campaigns](https://sendgrid.com/docs/User_Guide/Marketing_Campaigns/index.html) recipients. + +### GET /contactdb/recipients/billable_count + + +```javascript + request.method = 'GET'; + request.url = '/v3/contactdb/recipients/billable_count'; + client.request(request) + .then(([response, body]) => { + console.log(response.statusCode); + console.log(response.body); + }) +``` +## Retrieve a Count of Recipients + +**This endpoint allows you to retrieve the total number of Marketing Campaigns recipients.** + +The contactdb is a database of your contacts for [Twilio SendGrid Marketing Campaigns](https://sendgrid.com/docs/User_Guide/Marketing_Campaigns/index.html). + +### GET /contactdb/recipients/count + + +```javascript + request.method = 'GET'; + request.url = '/v3/contactdb/recipients/count'; + client.request(request) + .then(([response, body]) => { + console.log(response.statusCode); + console.log(response.body); + }) +``` +## Retrieve recipients matching search criteria + +**This endpoint allows you to perform a search on all of your Marketing Campaigns recipients.** + +field_name: + +* is a variable that is substituted for your actual custom field name from your recipient. +* Text fields must be URL encoded. Date fields are searchable only by Unix timestamp (e.g. 2/2/2015 becomes 1422835200) +* If field_name is a 'reserved' date field, such as created_at or updated_at, the system will internally convert +your epoch time to a date range encompassing the entire day. For example, an epoch time of 1422835600 converts to +Mon, 02 Feb 2015 00:06:40 GMT, but internally the system will search from Mon, 02 Feb 2015 00:00:00 GMT through +Mon, 02 Feb 2015 23:59:59 GMT. + +The contactdb is a database of your contacts for [Twilio SendGrid Marketing Campaigns](https://sendgrid.com/docs/User_Guide/Marketing_Campaigns/index.html). + +### GET /contactdb/recipients/search + + +```javascript + const queryParams = { + '{field_name}': 'test_string' +}; + request.qs = queryParams; + request.method = 'GET'; + request.url = '/v3/contactdb/recipients/search'; + client.request(request) + .then(([response, body]) => { + console.log(response.statusCode); + console.log(response.body); + }) +``` +## Delete a Recipient + +**This endpoint allows you to delete a single recipient with the given ID from your contact database.** + +The Contacts API helps you manage your [Marketing Campaigns](https://sendgrid.com/docs/User_Guide/Marketing_Campaigns/index.html) recipients. + +### DELETE /contactdb/recipients/{recipient_id} + + +```javascript + request.method = 'DELETE'; + request.url = '/v3/contactdb/recipients/{recipient_id}'; + client.request(request) + .then(([response, body]) => { + console.log(response.statusCode); + console.log(response.body); + }) +``` +## Retrieve a single recipient + +**This endpoint allows you to retrieve a single recipient by ID from your contact database.** + +The Contacts API helps you manage your [Marketing Campaigns](https://sendgrid.com/docs/User_Guide/Marketing_Campaigns/index.html) recipients. + +### GET /contactdb/recipients/{recipient_id} + + +```javascript + request.method = 'GET'; + request.url = '/v3/contactdb/recipients/{recipient_id}'; + client.request(request) + .then(([response, body]) => { + console.log(response.statusCode); + console.log(response.body); + }) +``` +## Retrieve the lists that a recipient is on + +**This endpoint allows you to retrieve the lists that a given recipient belongs to.** + +Each recipient can be on many lists. This endpoint gives you all of the lists that any one recipient has been added to. + +The Contacts API helps you manage your [Marketing Campaigns](https://sendgrid.com/docs/User_Guide/Marketing_Campaigns/index.html) recipients. + +### GET /contactdb/recipients/{recipient_id}/lists + + +```javascript + request.method = 'GET'; + request.url = '/v3/contactdb/recipients/{recipient_id}/lists'; + client.request(request) + .then(([response, body]) => { + console.log(response.statusCode); + console.log(response.body); + }) +``` +## Retrieve reserved fields + +**This endpoint allows you to list all fields that are reserved and can't be used for custom field names.** + +The contactdb is a database of your contacts for [Twilio SendGrid Marketing Campaigns](https://sendgrid.com/docs/User_Guide/Marketing_Campaigns/index.html). + +### GET /contactdb/reserved_fields + + +```javascript + request.method = 'GET'; + request.url = '/v3/contactdb/reserved_fields'; + client.request(request) + .then(([response, body]) => { + console.log(response.statusCode); + console.log(response.body); + }) +``` +## Create a Segment + +**This endpoint allows you to create a segment.** + +All recipients in your contactdb will be added or removed automatically depending on whether they match the criteria for this segment. + +List Id: + +* Send this to segment from an existing list. +* Don't send this to segment from your entire contactdb. + +Valid operators for create and update depend on the type of the field you are segmenting: + +* **Dates:** "eq", "ne", "lt" (before), "gt" (after) +* **Text:** "contains", "eq" (is - matches the full field), "ne" (is not - matches any field where the entire field is not the condition value) +* **Numbers:** "eq", "lt", "gt" +* **Email Clicks and Opens:** "eq" (opened), "ne" (not opened) + +Segment conditions using "eq" or "ne" for email clicks and opens should provide a "field" of either *clicks.campaign_identifier* or *opens.campaign_identifier*. The condition value should be a string containing the id of a completed campaign. + +Segments may contain multiple conditions, joined by an "and" or "or" in the "and_or" field. The first condition in the conditions list must have an empty "and_or", and subsequent conditions must all specify an "and_or". + +The Contacts API helps you manage your [Marketing Campaigns](https://sendgrid.com/docs/User_Guide/Marketing_Campaigns/index.html) recipients. + +For more information about segments in Marketing Campaigns, please see our [User Guide](https://sendgrid.com/docs/User_Guide/Marketing_Campaigns/lists.html#-Create-a-Segment). + +### POST /contactdb/segments + + +```javascript + const data = { + "conditions": [ + { + "and_or": "", + "field": "last_name", + "operator": "eq", + "value": "Miller" + }, + { + "and_or": "and", + "field": "last_clicked", + "operator": "gt", + "value": "01/02/2015" + }, + { + "and_or": "or", + "field": "clicks.campaign_identifier", + "operator": "eq", + "value": "513" + } + ], + "list_id": 4, + "name": "Last Name Miller" +}; + request.body = data; + request.method = 'POST'; + request.url = '/v3/contactdb/segments'; + client.request(request) + .then(([response, body]) => { + console.log(response.statusCode); + console.log(response.body); + }) +``` +## Retrieve all segments + +**This endpoint allows you to retrieve all of your segments.** + +The Contacts API helps you manage your [Marketing Campaigns](https://sendgrid.com/docs/User_Guide/Marketing_Campaigns/index.html) recipients. + +For more information about segments in Marketing Campaigns, please see our [User Guide](https://sendgrid.com/docs/User_Guide/Marketing_Campaigns/lists.html#-Create-a-Segment). + +### GET /contactdb/segments + + +```javascript + request.method = 'GET'; + request.url = '/v3/contactdb/segments'; + client.request(request) + .then(([response, body]) => { + console.log(response.statusCode); + console.log(response.body); + }) +``` +## Delete a segment + +**This endpoint allows you to delete a segment from your recipients' database.** + +You also have the option to delete all the contacts from your Marketing Campaigns recipient database who were in this segment. + +The Contacts API helps you manage your [Marketing Campaigns](https://sendgrid.com/docs/User_Guide/Marketing_Campaigns/index.html) recipients. + +For more information about segments in Marketing Campaigns, please see our [User Guide](https://sendgrid.com/docs/User_Guide/Marketing_Campaigns/lists.html#-Create-a-Segment). + +### DELETE /contactdb/segments/{segment_id} + + +```javascript + const queryParams = { + 'delete_contacts': 'true' +}; + request.qs = queryParams; + request.method = 'DELETE'; + request.url = '/v3/contactdb/segments/{segment_id}'; + client.request(request) + .then(([response, body]) => { + console.log(response.statusCode); + console.log(response.body); + }) +``` +## Update a segment + +**This endpoint allows you to update a segment.** + +The Contacts API helps you manage your [Marketing Campaigns](https://sendgrid.com/docs/User_Guide/Marketing_Campaigns/index.html) recipients. + +For more information about segments in Marketing Campaigns, please see our [User Guide](https://sendgrid.com/docs/User_Guide/Marketing_Campaigns/lists.html#-Create-a-Segment). + +### PATCH /contactdb/segments/{segment_id} + + +```javascript + const data = { + "conditions": [ + { + "and_or": "", + "field": "last_name", + "operator": "eq", + "value": "Miller" + } + ], + "list_id": 5, + "name": "The Millers" +}; + request.body = data; + const queryParams = { + 'segment_id': 'test_string' +}; + request.qs = queryParams; + request.method = 'PATCH'; + request.url = '/v3/contactdb/segments/{segment_id}'; + client.request(request) + .then(([response, body]) => { + console.log(response.statusCode); + console.log(response.body); + }) +``` +## Retrieve a segment + +**This endpoint allows you to retrieve a single segment with the given ID.** + +The Contacts API helps you manage your [Marketing Campaigns](https://sendgrid.com/docs/User_Guide/Marketing_Campaigns/index.html) recipients. + +For more information about segments in Marketing Campaigns, please see our [User Guide](https://sendgrid.com/docs/User_Guide/Marketing_Campaigns/lists.html#-Create-a-Segment). + +### GET /contactdb/segments/{segment_id} + + +```javascript + const queryParams = { + 'segment_id': 1 +}; + request.qs = queryParams; + request.method = 'GET'; + request.url = '/v3/contactdb/segments/{segment_id}'; + client.request(request) + .then(([response, body]) => { + console.log(response.statusCode); + console.log(response.body); + }) +``` +## Retrieve recipients on a segment + +**This endpoint allows you to retrieve all of the recipients in a segment with the given ID.** + +The Contacts API helps you manage your [Marketing Campaigns](https://sendgrid.com/docs/User_Guide/Marketing_Campaigns/index.html) recipients. + +For more information about segments in Marketing Campaigns, please see our [User Guide](https://sendgrid.com/docs/User_Guide/Marketing_Campaigns/lists.html#-Create-a-Segment). + +### GET /contactdb/segments/{segment_id}/recipients + + +```javascript + const queryParams = { + 'page': 1, + 'page_size': 1 +}; + request.qs = queryParams; + request.method = 'GET'; + request.url = '/v3/contactdb/segments/{segment_id}/recipients'; + client.request(request) + .then(([response, body]) => { + console.log(response.statusCode); + console.log(response.body); + }) +``` +## Get Contact Upload Status + + + +### GET /contactdb/status + + +```javascript + request.method = 'GET'; + request.url = '/v3/contactdb/status'; + client.request(request) + .then(([response, body]) => { + console.log(response.statusCode); + console.log(response.body); + }) +``` + +# DEVICES + +## Retrieve email statistics by device type. + +**This endpoint allows you to retrieve your email statistics segmented by the device type.** + +**We only store up to 7 days of email activity in our database.** By default, 500 items will be returned per request via the Advanced Stats API endpoints. + +## Available Device Types +| **Device** | **Description** | **Example** | +|---|---|---| +| Desktop | Email software on a desktop computer. | I.E., Outlook, Sparrow, or Apple Mail. | +| Webmail | A web-based email client. | I.E., Yahoo, Google, AOL, or Outlook.com. | +| Phone | A smartphone. | iPhone, Android, Blackberry, etc. +| Tablet | A tablet computer. | iPad, Android-based tablet, etc. | +| Other | An unrecognized device. | + +Advanced Stats provide a more in-depth view of your email statistics and the actions taken by your recipients. You can segment these statistics by geographic location, device type, client type, browser, and mailbox provider. For more information about statistics, please see our [User Guide](https://sendgrid.com/docs/User_Guide/Statistics/index.html). + +### GET /devices/stats + + +```javascript + const queryParams = { + 'aggregated_by': 'day', + 'end_date': '2016-04-01', + 'limit': 1, + 'offset': 1, + 'start_date': '2016-01-01' +}; + request.qs = queryParams; + request.method = 'GET'; + request.url = '/v3/devices/stats'; + client.request(request) + .then(([response, body]) => { + console.log(response.statusCode); + console.log(response.body); + }) +``` + +# GEO + +## Retrieve email statistics by country and state/province. + +**This endpoint allows you to retrieve your email statistics segmented by country and state/province.** + +**We only store up to 7 days of email activity in our database.** By default, 500 items will be returned per request via the Advanced Stats API endpoints. + +Advanced Stats provide a more in-depth view of your email statistics and the actions taken by your recipients. You can segment these statistics by geographic location, device type, client type, browser, and mailbox provider. For more information about statistics, please see our [User Guide](https://sendgrid.com/docs/User_Guide/Statistics/index.html). + +### GET /geo/stats + + +```javascript + const queryParams = { + 'aggregated_by': 'day', + 'country': 'US', + 'end_date': '2016-04-01', + 'limit': 1, + 'offset': 1, + 'start_date': '2016-01-01' +}; + request.qs = queryParams; + request.method = 'GET'; + request.url = '/v3/geo/stats'; + client.request(request) + .then(([response, body]) => { + console.log(response.statusCode); + console.log(response.body); + }) +``` + +# IPS + +## Add IPs + +This endpoint is for adding a(n) IP Address(es) to your account. + +### POST /ips + + +```javascript + const data = { + "count": 90323478, + "subusers": [ + "subuser1", + "subuser2" + ], + "user_can_send": true, + "warmup": true +}; + request.body = data; + request.method = 'POST'; + request.url = '/v3/ips'; + client.request(request) + .then(([response, body]) => { + console.log(response.statusCode); + console.log(response.body); + }) +``` +## Retrieve all IP addresses + +**This endpoint allows you to retrieve a list of all assigned and unassigned IPs.** + +The response includes warm-up status, pools, assigned subusers, and authentication info. The start_date field corresponds to when warmup started for that IP. + +A single IP address or a range of IP addresses may be dedicated to an account to send email for multiple domains. The reputation of this IP is based on the aggregate performance of all the senders who use it. + +### GET /ips + + +```javascript + const queryParams = { + 'exclude_whitelabels': 'true', + 'ip': 'test_string', + 'limit': 1, + 'offset': 1, + 'sort_by_direction': 'asc', + 'subuser': 'test_string' +}; + request.qs = queryParams; + request.method = 'GET'; + request.url = '/v3/ips'; + client.request(request) + .then(([response, body]) => { + console.log(response.statusCode); + console.log(response.body); + }) +``` +## Retrieve all assigned IPs + +**This endpoint allows you to retrieve only assigned IP addresses.** + +A single IP address or a range of IP addresses may be dedicated to an account to send email for multiple domains. The reputation of this IP is based on the aggregate performance of all the senders who use it. + +### GET /ips/assigned + + +```javascript + request.method = 'GET'; + request.url = '/v3/ips/assigned'; + client.request(request) + .then(([response, body]) => { + console.log(response.statusCode); + console.log(response.body); + }) +``` +## Create an IP pool. + +**This endpoint allows you to create an IP pool.** + +**Each user can create up to 10 different IP pools.** + +IP Pools allow you to group your dedicated Twilio SendGrid IP addresses. For example, you could create separate pools for your transactional and marketing email. When sending marketing emails, specify that you want to use the marketing IP pool. This allows you to maintain separate reputations for your different email traffic. + +IP pools can only be used with authenticated IP addresses. + +If an IP pool is NOT specified for an email, it will use any IP available, including ones in pools. + +### POST /ips/pools + + +```javascript + const data = { + "name": "marketing" +}; + request.body = data; + request.method = 'POST'; + request.url = '/v3/ips/pools'; + client.request(request) + .then(([response, body]) => { + console.log(response.statusCode); + console.log(response.body); + }) +``` +## Retrieve all IP pools. + +**This endpoint allows you to retrieve all of your IP pools.** + +IP Pools allow you to group your dedicated Twilio SendGrid IP addresses. For example, you could create separate pools for your transactional and marketing email. When sending marketing emails, specify that you want to use the marketing IP pool. This allows you to maintain separate reputations for your different email traffic. + +IP pools can only be used with authenticated IP addresses. + +If an IP pool is NOT specified for an email, it will use any IP available, including ones in pools. + +### GET /ips/pools + + +```javascript + request.method = 'GET'; + request.url = '/v3/ips/pools'; + client.request(request) + .then(([response, body]) => { + console.log(response.statusCode); + console.log(response.body); + }) +``` +## Update an IP pools name. + +**This endpoint allows you to update the name of an IP pool.** + +IP Pools allow you to group your dedicated Twilio SendGrid IP addresses. For example, you could create separate pools for your transactional and marketing email. When sending marketing emails, specify that you want to use the marketing IP pool. This allows you to maintain separate reputations for your different email traffic. + +IP pools can only be used with authenticated IP addresses. + +If an IP pool is NOT specified for an email, it will use any IP available, including ones in pools. + +### PUT /ips/pools/{pool_name} + + +```javascript + const data = { + "name": "new_pool_name" +}; + request.body = data; + request.method = 'PUT'; + request.url = '/v3/ips/pools/{pool_name}'; + client.request(request) + .then(([response, body]) => { + console.log(response.statusCode); + console.log(response.body); + }) +``` +## Delete an IP pool. + +**This endpoint allows you to delete an IP pool.** + +IP Pools allow you to group your dedicated Twilio SendGrid IP addresses. For example, you could create separate pools for your transactional and marketing email. When sending marketing emails, specify that you want to use the marketing IP pool. This allows you to maintain separate reputations for your different email traffic. + +IP pools can only be used with authenticated IP addresses. + +If an IP pool is NOT specified for an email, it will use any IP available, including ones in pools. + +### DELETE /ips/pools/{pool_name} + + +```javascript + request.method = 'DELETE'; + request.url = '/v3/ips/pools/{pool_name}'; + client.request(request) + .then(([response, body]) => { + console.log(response.statusCode); + console.log(response.body); + }) +``` +## Retrieve all IPs in a specified pool. + +**This endpoint allows you to list all of the IP addresses that are in a specific IP pool.** + +IP Pools allow you to group your dedicated Twilio SendGrid IP addresses. For example, you could create separate pools for your transactional and marketing email. When sending marketing emails, specify that you want to use the marketing IP pool. This allows you to maintain separate reputations for your different email traffic. + +IP pools can only be used with authenticated IP addresses. + +If an IP pool is NOT specified for an email, it will use any IP available, including ones in pools. + +### GET /ips/pools/{pool_name} + + +```javascript + request.method = 'GET'; + request.url = '/v3/ips/pools/{pool_name}'; + client.request(request) + .then(([response, body]) => { + console.log(response.statusCode); + console.log(response.body); + }) +``` +## Add an IP address to a pool + +**This endpoint allows you to add an IP address to an IP pool.** + +You can add the same IP address to multiple pools. It may take up to 60 seconds for your IP address to be added to a pool after your request is made. + +A single IP address or a range of IP addresses may be dedicated to an account to send email for multiple domains. The reputation of this IP is based on the aggregate performance of all the senders who use it. + +### POST /ips/pools/{pool_name}/ips + + +```javascript + const data = { + "ip": "0.0.0.0" +}; + request.body = data; + request.method = 'POST'; + request.url = '/v3/ips/pools/{pool_name}/ips'; + client.request(request) + .then(([response, body]) => { + console.log(response.statusCode); + console.log(response.body); + }) +``` +## Remove an IP address from a pool. + +**This endpoint allows you to remove an IP address from an IP pool.** + +The same IP address can be added to multiple IP pools. + +A single IP address or a range of IP addresses may be dedicated to an account to send email for multiple domains. The reputation of this IP is based on the aggregate performance of all the senders who use it. + +### DELETE /ips/pools/{pool_name}/ips/{ip} + + +```javascript + request.method = 'DELETE'; + request.url = '/v3/ips/pools/{pool_name}/ips/{ip}'; + client.request(request) + .then(([response, body]) => { + console.log(response.statusCode); + console.log(response.body); + }) +``` +## Get remaining IPs count + +This endpoint gets the amount of IP Addresses that can still be created during a given period and the price of those IPs. + +### GET /ips/remaining + + +```javascript + request.method = 'GET'; + request.url = '/v3/ips/remaining'; + client.request(request) + .then(([response, body]) => { + console.log(response.statusCode); + console.log(response.body); + }) +``` +## Add an IP to warmup + +**This endpoint allows you to enter an IP address into warmup mode.** + +Twilio SendGrid can automatically warm up dedicated IP addresses by limiting the amount of mail that can be sent through them per hour, with the limit determined by how long the IP address has been in warmup. See the [warmup schedule](https://sendgrid.com/docs/API_Reference/Web_API_v3/IP_Management/ip_warmup_schedule.html) for more details on how Twilio SendGrid limits your email traffic for IPs in warmup. + +For more general information about warming up IPs, please see our [Classroom](https://sendgrid.com/docs/Classroom/Deliver/Delivery_Introduction/warming_up_ips.html). + +### POST /ips/warmup + + +```javascript + const data = { + "ip": "0.0.0.0" +}; + request.body = data; + request.method = 'POST'; + request.url = '/v3/ips/warmup'; + client.request(request) + .then(([response, body]) => { + console.log(response.statusCode); + console.log(response.body); + }) +``` +## Retrieve all IPs currently in warmup + +**This endpoint allows you to retrieve all of your IP addresses that are currently warming up.** + +Twilio SendGrid can automatically warm up dedicated IP addresses by limiting the amount of mail that can be sent through them per hour, with the limit determined by how long the IP address has been in warmup. See the [warmup schedule](https://sendgrid.com/docs/API_Reference/Web_API_v3/IP_Management/ip_warmup_schedule.html) for more details on how Twilio SendGrid limits your email traffic for IPs in warmup. + +For more general information about warming up IPs, please see our [Classroom](https://sendgrid.com/docs/Classroom/Deliver/Delivery_Introduction/warming_up_ips.html). + +### GET /ips/warmup + + +```javascript + request.method = 'GET'; + request.url = '/v3/ips/warmup'; + client.request(request) + .then(([response, body]) => { + console.log(response.statusCode); + console.log(response.body); + }) +``` +## Remove an IP from warmup + +**This endpoint allows you to remove an IP address from warmup mode.** + +Twilio SendGrid can automatically warm up dedicated IP addresses by limiting the amount of mail that can be sent through them per hour, with the limit determined by how long the IP address has been in warmup. See the [warmup schedule](https://sendgrid.com/docs/API_Reference/Web_API_v3/IP_Management/ip_warmup_schedule.html) for more details on how Twilio SendGrid limits your email traffic for IPs in warmup. + +For more general information about warming up IPs, please see our [Classroom](https://sendgrid.com/docs/Classroom/Deliver/Delivery_Introduction/warming_up_ips.html). + +### DELETE /ips/warmup/{ip_address} + + +```javascript + request.method = 'DELETE'; + request.url = '/v3/ips/warmup/{ip_address}'; + client.request(request) + .then(([response, body]) => { + console.log(response.statusCode); + console.log(response.body); + }) +``` +## Retrieve warmup status for a specific IP address + +**This endpoint allows you to retrieve the warmup status for a specific IP address.** + +Twilio SendGrid can automatically warm up dedicated IP addresses by limiting the amount of mail that can be sent through them per hour, with the limit determined by how long the IP address has been in warmup. See the [warmup schedule](https://sendgrid.com/docs/API_Reference/Web_API_v3/IP_Management/ip_warmup_schedule.html) for more details on how Twilio SendGrid limits your email traffic for IPs in warmup. + +For more general information about warming up IPs, please see our [Classroom](https://sendgrid.com/docs/Classroom/Deliver/Delivery_Introduction/warming_up_ips.html). + +### GET /ips/warmup/{ip_address} + + +```javascript + request.method = 'GET'; + request.url = '/v3/ips/warmup/{ip_address}'; + client.request(request) + .then(([response, body]) => { + console.log(response.statusCode); + console.log(response.body); + }) +``` +## Retrieve all IP pools an IP address belongs to + +**This endpoint allows you to see which IP pools a particular IP address has been added to.** + +The same IP address can be added to multiple IP pools. + +A single IP address or a range of IP addresses may be dedicated to an account to send email for multiple domains. The reputation of this IP is based on the aggregate performance of all the senders who use it. + +### GET /ips/{ip_address} + + +```javascript + request.method = 'GET'; + request.url = '/v3/ips/{ip_address}'; + client.request(request) + .then(([response, body]) => { + console.log(response.statusCode); + console.log(response.body); + }) +``` + +# MAIL + +## Create a batch ID + +**This endpoint allows you to generate a new batch ID. This batch ID can be associated with scheduled sends via the mail/send endpoint.** + +If you set the SMTPAPI header `batch_id`, it allows you to then associate multiple scheduled mail/send requests together with the same ID. Then at any time up to 10 minutes before the scheduled date, you can cancel all of the mail/send requests that have this batch ID by calling the Cancel Scheduled Send endpoint. + +More Information: + +* [Scheduling Parameters > Batch ID](https://sendgrid.com/docs/API_Reference/SMTP_API/scheduling_parameters.html) + +### POST /mail/batch + + +```javascript + request.method = 'POST'; + request.url = '/v3/mail/batch'; + client.request(request) + .then(([response, body]) => { + console.log(response.statusCode); + console.log(response.body); + }) +``` +## Validate batch ID + +**This endpoint allows you to validate a batch ID.** + +If you set the SMTPAPI header `batch_id`, it allows you to then associate multiple scheduled mail/send requests together with the same ID. Then at any time up to 10 minutes before the scheduled date, you can cancel all of the mail/send requests that have this batch ID by calling the Cancel Scheduled Send endpoint. + +More Information: + +* [Scheduling Parameters > Batch ID](https://sendgrid.com/docs/API_Reference/SMTP_API/scheduling_parameters.html) + +### GET /mail/batch/{batch_id} + + +```javascript + request.method = 'GET'; + request.url = '/v3/mail/batch/{batch_id}'; + client.request(request) + .then(([response, body]) => { + console.log(response.statusCode); + console.log(response.body); + }) +``` +## v3 Mail Send + +This endpoint allows you to send an email over Twilio SendGrid's v3 Web API, the most recent version of our API. If you are looking for documentation about the v2 Mail Send endpoint, please see our [v2 API Reference](https://sendgrid.com/docs/API_Reference/Web_API/mail.html). + +* Top level parameters are referred to as "global". +* Individual fields within the personalizations array will override any other global, or message level, parameters that are defined outside of personalizations. + +**Twilio SendGrid provides libraries to help you quickly and easily integrate with the v3 Web API in 7 different languages: [C#](https://github.com/sendgrid/sendgrid-csharp), [Go](https://github.com/sendgrid/sendgrid-go), [Java](https://github.com/sendgrid/sendgrid-java), [Node JS](https://github.com/sendgrid/sendgrid-nodejs), [PHP](https://github.com/sendgrid/sendgrid-php), [Python](https://github.com/sendgrid/sendgrid-python), and [Ruby](https://github.com/sendgrid/sendgrid-ruby).** + + +For more detailed information about how to use the v3 Mail Send endpoint, please visit our [Classroom](https://sendgrid.com/docs/Classroom/Send/v3_Mail_Send/index.html). + +### POST /mail/send + +// This endpoint has a helper, check it out [here](../mail). + +```javascript + const data = { + "content": [ + { + "type": "text/html", + "value": "Hello, world!
" + } + ], + "from": { + "email": "sam.smith@example.com", + "name": "Sam Smith" + }, + "personalizations": [ + { + "subject": "Hello, World!", + "to": [ + { + "email": "john.doe@example.com", + "name": "John Doe" + } + ] + } + ], + "reply_to": { + "email": "sam.smith@example.com", + "name": "Sam Smith" + }, + "subject": "Hello, World!" +}; + request.body = data; + request.method = 'POST'; + request.url = '/v3/mail/send'; + client.request(request) + .then(([response, body]) => { + console.log(response.statusCode); + console.log(response.body); + }) +``` + +# MAIL SETTINGS + +## Retrieve all mail settings + +**This endpoint allows you to retrieve a list of all mail settings.** + +Mail settings allow you to tell Twilio SendGrid specific things to do to every email that you send to your recipients over Twilio SendGrid's [Web API](https://sendgrid.com/docs/API_Reference/Web_API/mail.html) or [SMTP Relay](https://sendgrid.com/docs/API_Reference/SMTP_API/index.html). + +### GET /mail_settings + + +```javascript + const queryParams = { + 'limit': 1, + 'offset': 1 +}; + request.qs = queryParams; + request.method = 'GET'; + request.url = '/v3/mail_settings'; + client.request(request) + .then(([response, body]) => { + console.log(response.statusCode); + console.log(response.body); + }) +``` +## Update address whitelist mail settings + +**This endpoint allows you to update your current email address whitelist settings.** + +The address whitelist setting whitelists a specified email address or domain for which mail should never be suppressed. For example, you own the domain example.com, and one or more of your recipients use email@example.com addresses, by placing example.com in the address whitelist setting, all bounces, blocks, and unsubscribes logged for that domain will be ignored and sent as if under normal sending conditions. + +Mail settings allow you to tell Twilio SendGrid specific things to do to every email that you send to your recipients over Twilio SendGrid's [Web API](https://sendgrid.com/docs/API_Reference/Web_API/mail.html) or [SMTP Relay](https://sendgrid.com/docs/API_Reference/SMTP_API/index.html). + +### PATCH /mail_settings/address_whitelist + + +```javascript + const data = { + "enabled": true, + "list": [ + "email1@example.com", + "example.com" + ] +}; + request.body = data; + request.method = 'PATCH'; + request.url = '/v3/mail_settings/address_whitelist'; + client.request(request) + .then(([response, body]) => { + console.log(response.statusCode); + console.log(response.body); + }) +``` +## Retrieve address whitelist mail settings + +**This endpoint allows you to retrieve your current email address whitelist settings.** + +The address whitelist setting whitelists a specified email address or domain for which mail should never be suppressed. For example, you own the domain example.com, and one or more of your recipients use email@example.com addresses, by placing example.com in the address whitelist setting, all bounces, blocks, and unsubscribes logged for that domain will be ignored and sent as if under normal sending conditions. + +Mail settings allow you to tell Twilio SendGrid specific things to do to every email that you send to your recipients over Twilio SendGrid's [Web API](https://sendgrid.com/docs/API_Reference/Web_API/mail.html) or [SMTP Relay](https://sendgrid.com/docs/API_Reference/SMTP_API/index.html). + +### GET /mail_settings/address_whitelist + + +```javascript + request.method = 'GET'; + request.url = '/v3/mail_settings/address_whitelist'; + client.request(request) + .then(([response, body]) => { + console.log(response.statusCode); + console.log(response.body); + }) +``` +## Update BCC mail settings + +**This endpoint allows you to update your current BCC mail settings.** + +When the BCC mail setting is enabled, Twilio SendGrid will automatically send a blind carbon copy (BCC) to an address for every email sent without adding that address to the header. Please note that only one email address may be entered in this field if you wish to distribute BCCs to multiple addresses you will need to create a distribution group or use forwarding rules. + +Mail settings allow you to tell Twilio SendGrid specific things to do to every email that you send to your recipients over Twilio SendGrid's [Web API](https://sendgrid.com/docs/API_Reference/Web_API/mail.html) or [SMTP Relay](https://sendgrid.com/docs/API_Reference/SMTP_API/index.html). + +### PATCH /mail_settings/bcc + + +```javascript + const data = { + "email": "email@example.com", + "enabled": false +}; + request.body = data; + request.method = 'PATCH'; + request.url = '/v3/mail_settings/bcc'; + client.request(request) + .then(([response, body]) => { + console.log(response.statusCode); + console.log(response.body); + }) +``` +## Retrieve all BCC mail settings + +**This endpoint allows you to retrieve your current BCC mail settings.** + +When the BCC mail setting is enabled, Twilio SendGrid will automatically send a blind carbon copy (BCC) to an address for every email sent without adding that address to the header. Please note that only one email address may be entered in this field if you wish to distribute BCCs to multiple addresses you will need to create a distribution group or use forwarding rules. + +Mail settings allow you to tell Twilio SendGrid specific things to do to every email that you send to your recipients over Twilio SendGrid's [Web API](https://sendgrid.com/docs/API_Reference/Web_API/mail.html) or [SMTP Relay](https://sendgrid.com/docs/API_Reference/SMTP_API/index.html). + +### GET /mail_settings/bcc + + +```javascript + request.method = 'GET'; + request.url = '/v3/mail_settings/bcc'; + client.request(request) + .then(([response, body]) => { + console.log(response.statusCode); + console.log(response.body); + }) +``` +## Update bounce purge mail settings + +**This endpoint allows you to update your current bounce purge settings.** + +This setting allows you to set a schedule for Twilio SendGrid to automatically delete contacts from your soft and hard bounce suppression lists. + +Mail settings allow you to tell Twilio SendGrid specific things to do to every email that you send to your recipients over Twilio SendGrid's [Web API](https://sendgrid.com/docs/API_Reference/Web_API/mail.html) or [SMTP Relay](https://sendgrid.com/docs/API_Reference/SMTP_API/index.html). + +### PATCH /mail_settings/bounce_purge + + +```javascript + const data = { + "enabled": true, + "hard_bounces": 5, + "soft_bounces": 5 +}; + request.body = data; + request.method = 'PATCH'; + request.url = '/v3/mail_settings/bounce_purge'; + client.request(request) + .then(([response, body]) => { + console.log(response.statusCode); + console.log(response.body); + }) +``` +## Retrieve bounce purge mail settings + +**This endpoint allows you to retrieve your current bounce purge settings.** + +This setting allows you to set a schedule for Twilio SendGrid to automatically delete contacts from your soft and hard bounce suppression lists. + +Mail settings allow you to tell Twilio SendGrid specific things to do to every email that you send to your recipients over Twilio SendGrid's [Web API](https://sendgrid.com/docs/API_Reference/Web_API/mail.html) or [SMTP Relay](https://sendgrid.com/docs/API_Reference/SMTP_API/index.html). + +### GET /mail_settings/bounce_purge + + +```javascript + request.method = 'GET'; + request.url = '/v3/mail_settings/bounce_purge'; + client.request(request) + .then(([response, body]) => { + console.log(response.statusCode); + console.log(response.body); + }) +``` +## Update footer mail settings + +**This endpoint allows you to update your current Footer mail settings.** + +The footer setting will insert a custom footer at the bottom of the text and HTML bodies. Use the embedded HTML editor and plain text entry fields to create the content of the footers to be inserted into your emails. + +Mail settings allow you to tell Twilio SendGrid specific things to do to every email that you send to your recipients over Twilio SendGrid's [Web API](https://sendgrid.com/docs/API_Reference/Web_API/mail.html) or [SMTP Relay](https://sendgrid.com/docs/API_Reference/SMTP_API/index.html). + +### PATCH /mail_settings/footer + + +```javascript + const data = { + "enabled": true, + "html_content": "...", + "plain_content": "..." +}; + request.body = data; + request.method = 'PATCH'; + request.url = '/v3/mail_settings/footer'; + client.request(request) + .then(([response, body]) => { + console.log(response.statusCode); + console.log(response.body); + }) +``` +## Retrieve footer mail settings + +**This endpoint allows you to retrieve your current Footer mail settings.** + +The footer setting will insert a custom footer at the bottom of the text and HTML bodies. Use the embedded HTML editor and plain text entry fields to create the content of the footers to be inserted into your emails. + +Mail settings allow you to tell Twilio SendGrid specific things to do to every email that you send to your recipients over Twilio SendGrid's [Web API](https://sendgrid.com/docs/API_Reference/Web_API/mail.html) or [SMTP Relay](https://sendgrid.com/docs/API_Reference/SMTP_API/index.html). + +### GET /mail_settings/footer + + +```javascript + request.method = 'GET'; + request.url = '/v3/mail_settings/footer'; + client.request(request) + .then(([response, body]) => { + console.log(response.statusCode); + console.log(response.body); + }) +``` +## Update forward bounce mail settings + +**This endpoint allows you to update your current bounce forwarding mail settings.** + +Activating this setting allows you to specify an email address to which bounce reports are forwarded. + +Mail settings allow you to tell Twilio SendGrid specific things to do to every email that you send to your recipients over Twilio SendGrid's [Web API](https://sendgrid.com/docs/API_Reference/Web_API/mail.html) or [SMTP Relay](https://sendgrid.com/docs/API_Reference/SMTP_API/index.html). + +### PATCH /mail_settings/forward_bounce + + +```javascript + const data = { + "email": "example@example.com", + "enabled": true +}; + request.body = data; + request.method = 'PATCH'; + request.url = '/v3/mail_settings/forward_bounce'; + client.request(request) + .then(([response, body]) => { + console.log(response.statusCode); + console.log(response.body); + }) +``` +## Retrieve forward bounce mail settings + +**This endpoint allows you to retrieve your current bounce forwarding mail settings.** + +Activating this setting allows you to specify an email address to which bounce reports are forwarded. + +Mail settings allow you to tell Twilio SendGrid specific things to do to every email that you send to your recipients over Twilio SendGrid's [Web API](https://sendgrid.com/docs/API_Reference/Web_API/mail.html) or [SMTP Relay](https://sendgrid.com/docs/API_Reference/SMTP_API/index.html). + +### GET /mail_settings/forward_bounce + + +```javascript + request.method = 'GET'; + request.url = '/v3/mail_settings/forward_bounce'; + client.request(request) + .then(([response, body]) => { + console.log(response.statusCode); + console.log(response.body); + }) +``` +## Update forward spam mail settings + +**This endpoint allows you to update your current Forward Spam mail settings.** + +Enabling the forward spam setting allows you to specify an email address to which spam reports will be forwarded. + +Mail settings allow you to tell Twilio SendGrid specific things to do to every email that you send to your recipients over Twilio SendGrid's [Web API](https://sendgrid.com/docs/API_Reference/Web_API/mail.html) or [SMTP Relay](https://sendgrid.com/docs/API_Reference/SMTP_API/index.html). + +### PATCH /mail_settings/forward_spam + + +```javascript + const data = { + "email": "", + "enabled": false +}; + request.body = data; + request.method = 'PATCH'; + request.url = '/v3/mail_settings/forward_spam'; + client.request(request) + .then(([response, body]) => { + console.log(response.statusCode); + console.log(response.body); + }) +``` +## Retrieve forward spam mail settings + +**This endpoint allows you to retrieve your current Forward Spam mail settings.** + +Enabling the forward spam setting allows you to specify an email address to which spam reports will be forwarded. + +Mail settings allow you to tell Twilio SendGrid specific things to do to every email that you send to your recipients over Twilio SendGrid's [Web API](https://sendgrid.com/docs/API_Reference/Web_API/mail.html) or [SMTP Relay](https://sendgrid.com/docs/API_Reference/SMTP_API/index.html). + +### GET /mail_settings/forward_spam + + +```javascript + request.method = 'GET'; + request.url = '/v3/mail_settings/forward_spam'; + client.request(request) + .then(([response, body]) => { + console.log(response.statusCode); + console.log(response.body); + }) +``` +## Update plain content mail settings + +**This endpoint allows you to update your current Plain Content mail settings.** + +The plain content setting will automatically convert any plain text emails that you send to HTML before sending. + +Mail settings allow you to tell Twilio SendGrid specific things to do to every email that you send to your recipients over Twilio SendGrid's [Web API](https://sendgrid.com/docs/API_Reference/Web_API/mail.html) or [SMTP Relay](https://sendgrid.com/docs/API_Reference/SMTP_API/index.html). + +### PATCH /mail_settings/plain_content + + +```javascript + const data = { + "enabled": false +}; + request.body = data; + request.method = 'PATCH'; + request.url = '/v3/mail_settings/plain_content'; + client.request(request) + .then(([response, body]) => { + console.log(response.statusCode); + console.log(response.body); + }) +``` +## Retrieve plain content mail settings + +**This endpoint allows you to retrieve your current Plain Content mail settings.** + +The plain content setting will automatically convert any plain text emails that you send to HTML before sending. + +Mail settings allow you to tell Twilio SendGrid specific things to do to every email that you send to your recipients over Twilio SendGrid's [Web API](https://sendgrid.com/docs/API_Reference/Web_API/mail.html) or [SMTP Relay](https://sendgrid.com/docs/API_Reference/SMTP_API/index.html). + +### GET /mail_settings/plain_content + + +```javascript + request.method = 'GET'; + request.url = '/v3/mail_settings/plain_content'; + client.request(request) + .then(([response, body]) => { + console.log(response.statusCode); + console.log(response.body); + }) +``` +## Update spam check mail settings + +**This endpoint allows you to update your current spam checker mail settings.** + +The spam checker filter notifies you when emails are detected that exceed a predefined spam threshold. + +Mail settings allow you to tell Twilio SendGrid specific things to do to every email that you send to your recipients over Twilio SendGrid's [Web API](https://sendgrid.com/docs/API_Reference/Web_API/mail.html) or [SMTP Relay](https://sendgrid.com/docs/API_Reference/SMTP_API/index.html). + +### PATCH /mail_settings/spam_check + + +```javascript + const data = { + "enabled": true, + "max_score": 5, + "url": "url" +}; + request.body = data; + request.method = 'PATCH'; + request.url = '/v3/mail_settings/spam_check'; + client.request(request) + .then(([response, body]) => { + console.log(response.statusCode); + console.log(response.body); + }) +``` +## Retrieve spam check mail settings + +**This endpoint allows you to retrieve your current Spam Checker mail settings.** + +The spam checker filter notifies you when emails are detected that exceed a predefined spam threshold. + +Mail settings allow you to tell Twilio SendGrid specific things to do to every email that you send to your recipients over Twilio SendGrid's [Web API](https://sendgrid.com/docs/API_Reference/Web_API/mail.html) or [SMTP Relay](https://sendgrid.com/docs/API_Reference/SMTP_API/index.html). + +### GET /mail_settings/spam_check + + +```javascript + request.method = 'GET'; + request.url = '/v3/mail_settings/spam_check'; + client.request(request) + .then(([response, body]) => { + console.log(response.statusCode); + console.log(response.body); + }) +``` +## Update template mail settings + +**This endpoint allows you to update your current legacy email template settings.** + +This setting refers to our original email templates. We currently support more fully featured [transactional templates](https://sendgrid.com/docs/User_Guide/Transactional_Templates/index.html). + +The legacy email template setting wraps an HTML template around your email content. This can be useful for sending out marketing email and/or other HTML formatted messages. + +Mail settings allow you to tell Twilio SendGrid specific things to do to every email that you send to your recipients over Twilio SendGrid's [Web API](https://sendgrid.com/docs/API_Reference/Web_API/mail.html) or [SMTP Relay](https://sendgrid.com/docs/API_Reference/SMTP_API/index.html). + +### PATCH /mail_settings/template + + +```javascript + const data = { + "enabled": true, + "html_content": "<% body %>" +}; + request.body = data; + request.method = 'PATCH'; + request.url = '/v3/mail_settings/template'; + client.request(request) + .then(([response, body]) => { + console.log(response.statusCode); + console.log(response.body); + }) +``` +## Retrieve legacy template mail settings + +**This endpoint allows you to retrieve your current legacy email template settings.** + +This setting refers to our original email templates. We currently support more fully featured [transactional templates](https://sendgrid.com/docs/User_Guide/Transactional_Templates/index.html). + +The legacy email template setting wraps an HTML template around your email content. This can be useful for sending out marketing email and/or other HTML formatted messages. + +Mail settings allow you to tell Twilio SendGrid specific things to do to every email that you send to your recipients over Twilio SendGrid's [Web API](https://sendgrid.com/docs/API_Reference/Web_API/mail.html) or [SMTP Relay](https://sendgrid.com/docs/API_Reference/SMTP_API/index.html). + +### GET /mail_settings/template + + +```javascript + request.method = 'GET'; + request.url = '/v3/mail_settings/template'; + client.request(request) + .then(([response, body]) => { + console.log(response.statusCode); + console.log(response.body); + }) +``` + +# MAILBOX PROVIDERS + +## Retrieve email statistics by mailbox provider. + +**This endpoint allows you to retrieve your email statistics segmented by recipient mailbox provider.** + +**We only store up to 7 days of email activity in our database.** By default, 500 items will be returned per request via the Advanced Stats API endpoints. + +Advanced Stats provide a more in-depth view of your email statistics and the actions taken by your recipients. You can segment these statistics by geographic location, device type, client type, browser, and mailbox provider. For more information about statistics, please see our [User Guide](https://sendgrid.com/docs/User_Guide/Statistics/index.html). + +### GET /mailbox_providers/stats + + +```javascript + const queryParams = { + 'aggregated_by': 'day', + 'end_date': '2016-04-01', + 'limit': 1, + 'mailbox_providers': 'test_string', + 'offset': 1, + 'start_date': '2016-01-01' +}; + request.qs = queryParams; + request.method = 'GET'; + request.url = '/v3/mailbox_providers/stats'; + client.request(request) + .then(([response, body]) => { + console.log(response.statusCode); + console.log(response.body); + }) +``` + +# MESSAGES + +## Filter all messages +> In order to gain access to the Email Activity Feed API, you must purchase [additional email activity history](https://app.sendgrid.com/settings/billing/addons/email_activity). + +Filter all messages to search your Email Activity. All queries need to be [URL encoded](https://meyerweb.com/eric/tools/dencoder/), and have this format: + +`query={query_type}="{query_content}"` + +encoded, this would look like this: + +`query=type%3D%22query_content%22` + +for example: + +Filter by a specific email - `query=to_email%3D%22example%40example.com%22` + +Filter by subject line - `query=subject%3d%22A%20Great%20Subject%22` + +You can filter by other operators besides `=`. We also accept `!=`, `<`, and `>`. + +If you use the `@sendgrid/client` library, you do not have to encode anything (it will end up being double encoded). + +For a tutorial on how to get started, check out [Getting Started with the Email Activity API](https://sendgrid.com/docs/API_Reference/Web_API_v3/Tutorials/getting_started_email_activity_api.html). + +**Full list of basic query types and examples:** +(replace the data in quotes with the information you want to query) + +Query | +Unencoded example (put this one into the try it out query - it'll automatically encode it for you) | +Encoded example (use this one in your code) | +
---|---|---|
msg_id |
+ msg_id="filter0307p1las1-16816-5A023E36-1.0" |
+ msg_id%3D%22filter0307p1las1-16816-5A023E36-1.0%22 |
+
from_email |
+ from_email="testing@sendgrid.net" |
+ from_email%3D%22testing%40sendgrid.net%22 |
+
subject |
+ subject="This is a subject test" |
+ subject%22This%20is%20a%20subject%20test%22 |
+
to_email |
+ to_email="example@example.com" |
+ to_email%3D%22example%40example.com%22 |
+
status |
+ status="processed" |
+ status%22processed%22 |
+
template_id |
+ template_id="8f0d27bc-cf8f-42d3-b951-3990af7d0619" |
+ template_id%3D%228f0d27bc-cf8f-42d3-b951-3990af7d0619%22 |
+
template_name |
+ template_name="example_template" |
+ template_name%3D%22example_template%22 |
+
campaign_name |
+ campaign_name="example_campaign" |
+ campaign_name%3D%22example_campaign%22 |
+
campaign_id |
+ campaign_id="1453849" |
+ campaign_id%3D%221453849%22 |
+
api_key_id |
+ api_key_id="-hVjtoFgGUNPq3DPPPkJN3mCIDIwrl3qdFZcqYKnlq94" (everything after the middle dot in the API key) |
+ api_key_id%3D%22-hVjtoFgGUNPq3DPPPkJN3mCIDIwrl3qdFZcqYKnlq94%22 |
+
api_key_name |
+ api_key_name="test_name" |
+ api_key_name%3D%22test_name%22 |
+
events |
+ status="processed" |
+ status%3D%22processed%22 |
+
originating_ip - this is the IP address of the person sending the message |
+ originating_ip="4.77.777.77" |
+ originating_ip%3D%224.77.777.77%22 |
+
categories - custom tags that you create |
+ categories="category_example" |
+ categories="category_example" |
+
unique_args - custom tracking arguments that you can attach to SMTP API calls |
+ unique_args="example argument" |
+ unique_args%3D%22example%20argument%22 |
+
outbound_ip - this is the Twilio SendGrid dedicated IP address used to send the email |
+ outbound_ip="4.77.777.77" |
+ outbound_ip%3D%224.77.777.77%22 |
+
last_event_time |
+ last_event_time="2017-11-07T23:13:58Z" |
+ last_event_time%3D%E2%80%9C2017-11-07T23%3A13%3A58Z%E2%80%9D |
+
clicks |
+ clicks="0" |
+ clicks%3D%220%22 |
+
unsubscribe_group_name |
+ unsubscribe_group_name="Global Unsubscribes" |
+ unsubscribe_group_name%3D%22Global%20Unsubscribes%22 |
+
unsubscribe_group_id |
+ unsubscribe_group_id="1041" |
+ unsubscribe_group_id%3D%221041%22 |
+
teammate - teamates username |
+ teammate="my_username" |
+ teammate%3D%22my_username%22 |
+
Check out our spring line!
', + ip_pool: 'marketing', + list_ids: [ + 110, + 124, + ], + plain_content: 'Check out our spring line!', + segment_ids: [ + 110, + ], + sender_id: 124451, + subject: 'New Products for Spring!', + suppression_group_id: 42, + title: 'March Newsletter', + }; + request.method = 'POST'; + request.url = '/v3/campaigns'; + it('should have the correct response code', () => { + return testRequest(request, 201); + }); +}); + +describe('test_campaigns_get', () => { + const request = {}; + request.qs = { + limit: 1, + offset: 1, + }; + request.method = 'GET'; + request.url = '/v3/campaigns'; + it('should have the correct response code', () => { + return testRequest(request, 200); + }); +}); + +describe('test_campaigns__campaign_id__patch', () => { + const request = {}; + request.body = { + categories: [ + 'summer line', + ], + html_content: 'Check out our summer line!
', + plain_content: 'Check out our summer line!', + subject: 'New Products for Summer!', + title: 'May Newsletter', + }; + request.method = 'PATCH'; + request.url = '/v3/campaigns/{campaign_id}'; + it('should have the correct response code', () => { + return testRequest(request, 200); + }); +}); + +describe('test_campaigns__campaign_id__delete', () => { + const request = {}; + request.method = 'DELETE'; + request.url = '/v3/campaigns/{campaign_id}'; + xit('should have the correct response code', () => { + return testRequest(request, 204); + }); +}); + +describe('test_campaigns__campaign_id__get', () => { + const request = {}; + request.method = 'GET'; + request.url = '/v3/campaigns/{campaign_id}'; + it('should have the correct response code', () => { + return testRequest(request, 200); + }); +}); + +describe('test_campaigns__campaign_id__schedules_delete', () => { + const request = {}; + request.method = 'DELETE'; + request.url = '/v3/campaigns/{campaign_id}/schedules'; + xit('should have the correct response code', () => { + return testRequest(request, 204); + }); +}); + +describe('test_campaigns__campaign_id__schedules_post', () => { + const request = {}; + request.body = { + send_at: 1489771528, + }; + request.method = 'POST'; + request.url = '/v3/campaigns/{campaign_id}/schedules'; + it('should have the correct response code', () => { + return testRequest(request, 201); + }); +}); + +describe('test_campaigns__campaign_id__schedules_get', () => { + const request = {}; + request.method = 'GET'; + request.url = '/v3/campaigns/{campaign_id}/schedules'; + it('should have the correct response code', () => { + return testRequest(request, 200); + }); +}); + +describe('test_campaigns__campaign_id__schedules_patch', () => { + const request = {}; + request.body = { + send_at: 1489451436, + }; + request.method = 'PATCH'; + request.url = '/v3/campaigns/{campaign_id}/schedules'; + it('should have the correct response code', () => { + return testRequest(request, 200); + }); +}); + +describe('test_campaigns__campaign_id__schedules_now_post', () => { + const request = {}; + request.method = 'POST'; + request.url = '/v3/campaigns/{campaign_id}/schedules/now'; + it('should have the correct response code', () => { + return testRequest(request, 201); + }); +}); + +describe('test_campaigns__campaign_id__schedules_test_post', () => { + const request = {}; + request.body = { + to: 'your.email@example.com', + }; + request.method = 'POST'; + request.url = '/v3/campaigns/{campaign_id}/schedules/test'; + xit('should have the correct response code', () => { + return testRequest(request, 204); + }); +}); + +describe('test_categories_get', () => { + const request = {}; + request.qs = { + category: 'test_string', + limit: 1, + offset: 1, + }; + request.method = 'GET'; + request.url = '/v3/categories'; + it('should have the correct response code', () => { + return testRequest(request, 200); + }); +}); + +describe('test_categories_stats_get', () => { + const request = {}; + request.qs = { + aggregated_by: 'day', + categories: 'test_string', + end_date: '2016-04-01', + limit: 1, + offset: 1, + start_date: '2016-01-01', + }; + request.method = 'GET'; + request.url = '/v3/categories/stats'; + it('should have the correct response code', () => { + return testRequest(request, 200); + }); +}); + +describe('test_categories_stats_sums_get', () => { + const request = {}; + request.qs = { + aggregated_by: 'day', + end_date: '2016-04-01', + limit: 1, + offset: 1, + sort_by_direction: 'asc', + sort_by_metric: 'test_string', + start_date: '2016-01-01', + }; + request.method = 'GET'; + request.url = '/v3/categories/stats/sums'; + it('should have the correct response code', () => { + return testRequest(request, 200); + }); +}); + +describe('test_clients_stats_get', () => { + const request = {}; + request.qs = { + aggregated_by: 'day', + end_date: '2016-04-01', + start_date: '2016-01-01', + }; + request.method = 'GET'; + request.url = '/v3/clients/stats'; + it('should have the correct response code', () => { + return testRequest(request, 200); + }); +}); + +describe('test_clients__client_type__stats_get', () => { + const request = {}; + request.qs = { + aggregated_by: 'day', + end_date: '2016-04-01', + start_date: '2016-01-01', + }; + request.method = 'GET'; + request.url = '/v3/clients/{client_type}/stats'; + it('should have the correct response code', () => { + return testRequest(request, 200); + }); +}); + +describe('test_contactdb_custom_fields_post', () => { + const request = {}; + request.body = { + name: 'pet', + type: 'text', + }; + request.method = 'POST'; + request.url = '/v3/contactdb/custom_fields'; + it('should have the correct response code', () => { + return testRequest(request, 201); + }); +}); + +describe('test_contactdb_custom_fields_get', () => { + const request = {}; + request.method = 'GET'; + request.url = '/v3/contactdb/custom_fields'; + it('should have the correct response code', () => { + return testRequest(request, 200); + }); +}); + +describe('test_contactdb_custom_fields__custom_field_id__delete', () => { + const request = {}; + request.method = 'DELETE'; + request.url = '/v3/contactdb/custom_fields/{custom_field_id}'; + it('should have the correct response code', () => { + return testRequest(request, 202); + }); +}); + +describe('test_contactdb_custom_fields__custom_field_id__get', () => { + const request = {}; + request.method = 'GET'; + request.url = '/v3/contactdb/custom_fields/{custom_field_id}'; + it('should have the correct response code', () => { + return testRequest(request, 200); + }); +}); + +describe('test_contactdb_lists_post', () => { + const request = {}; + request.body = { + name: 'your list name', + }; + request.method = 'POST'; + request.url = '/v3/contactdb/lists'; + it('should have the correct response code', () => { + return testRequest(request, 201); + }); +}); + +describe('test_contactdb_lists_delete', () => { + const request = {}; + request.body = [ + 1, + 2, + 3, + 4, + ]; + request.method = 'DELETE'; + request.url = '/v3/contactdb/lists'; + xit('should have the correct response code', () => { + return testRequest(request, 204); + }); +}); + +describe('test_contactdb_lists_get', () => { + const request = {}; + request.method = 'GET'; + request.url = '/v3/contactdb/lists'; + it('should have the correct response code', () => { + return testRequest(request, 200); + }); +}); + +describe('test_contactdb_lists__list_id__delete', () => { + const request = {}; + request.qs = { + delete_contacts: 'true', + }; + request.method = 'DELETE'; + request.url = '/v3/contactdb/lists/{list_id}'; + it('should have the correct response code', () => { + return testRequest(request, 202); + }); +}); + +describe('test_contactdb_lists__list_id__patch', () => { + const request = {}; + request.body = { + name: 'newlistname', + }; + request.qs = { + list_id: 1, + }; + request.method = 'PATCH'; + request.url = '/v3/contactdb/lists/{list_id}'; + it('should have the correct response code', () => { + return testRequest(request, 200); + }); +}); + +describe('test_contactdb_lists__list_id__get', () => { + const request = {}; + request.qs = { + list_id: 1, + }; + request.method = 'GET'; + request.url = '/v3/contactdb/lists/{list_id}'; + it('should have the correct response code', () => { + return testRequest(request, 200); + }); +}); + +describe('test_contactdb_lists__list_id__recipients_post', () => { + const request = {}; + request.body = [ + 'recipient_id1', + 'recipient_id2', + ]; + request.method = 'POST'; + request.url = '/v3/contactdb/lists/{list_id}/recipients'; + it('should have the correct response code', () => { + return testRequest(request, 201); + }); +}); + +describe('test_contactdb_lists__list_id__recipients_get', () => { + const request = {}; + request.qs = { + list_id: 1, + page: 1, + page_size: 1, + }; + request.method = 'GET'; + request.url = '/v3/contactdb/lists/{list_id}/recipients'; + it('should have the correct response code', () => { + return testRequest(request, 200); + }); +}); + +describe('test_contactdb_lists__list_id__recipients__recipient_id__post', () => { + const request = {}; + request.method = 'POST'; + request.url = '/v3/contactdb/lists/{list_id}/recipients/{recipient_id}'; + it('should have the correct response code', () => { + return testRequest(request, 201); + }); +}); + +describe('test_contactdb_lists__list_id__recipients__recipient_id__delete', () => { + const request = {}; + request.qs = { + list_id: 1, + recipient_id: 1, + }; + request.method = 'DELETE'; + request.url = '/v3/contactdb/lists/{list_id}/recipients/{recipient_id}'; + xit('should have the correct response code', () => { + return testRequest(request, 204); + }); +}); + +describe('test_contactdb_recipients_post', () => { + const request = {}; + request.body = [ + { + age: 25, + email: 'example@example.com', + first_name: '', + last_name: 'User', + }, + { + age: 25, + email: 'example2@example.com', + first_name: 'Example', + last_name: 'User', + }, + ]; + request.method = 'POST'; + request.url = '/v3/contactdb/recipients'; + it('should have the correct response code', () => { + return testRequest(request, 201); + }); +}); + +describe('test_contactdb_recipients_delete', () => { + const request = {}; + request.body = [ + 'recipient_id1', + 'recipient_id2', + ]; + request.method = 'DELETE'; + request.url = '/v3/contactdb/recipients'; + it('should have the correct response code', () => { + return testRequest(request, 200); + }); +}); + +describe('test_contactdb_recipients_get', () => { + const request = {}; + request.qs = { + page: 1, + page_size: 1, + }; + request.method = 'GET'; + request.url = '/v3/contactdb/recipients'; + it('should have the correct response code', () => { + return testRequest(request, 200); + }); +}); + +describe('test_contactdb_recipients_patch', () => { + const request = {}; + request.body = [ + { + email: 'jones@example.com', + first_name: 'Guy', + last_name: 'Jones', + }, + ]; + request.method = 'PATCH'; + request.url = '/v3/contactdb/recipients'; + it('should have the correct response code', () => { + return testRequest(request, 201); + }); +}); + +describe('test_contactdb_recipients_billable_count_get', () => { + const request = {}; + request.method = 'GET'; + request.url = '/v3/contactdb/recipients/billable_count'; + it('should have the correct response code', () => { + return testRequest(request, 200); + }); +}); + +describe('test_contactdb_recipients_count_get', () => { + const request = {}; + request.method = 'GET'; + request.url = '/v3/contactdb/recipients/count'; + it('should have the correct response code', () => { + return testRequest(request, 200); + }); +}); + +describe('test_contactdb_recipients_search_get', () => { + const request = {}; + request.qs = { + '{field_name}': 'test_string', + }; + request.method = 'GET'; + request.url = '/v3/contactdb/recipients/search'; + it('should have the correct response code', () => { + return testRequest(request, 200); + }); +}); + +describe('test_contactdb_recipients__recipient_id__delete', () => { + const request = {}; + request.method = 'DELETE'; + request.url = '/v3/contactdb/recipients/{recipient_id}'; + xit('should have the correct response code', () => { + return testRequest(request, 204); + }); +}); + +describe('test_contactdb_recipients__recipient_id__get', () => { + const request = {}; + request.method = 'GET'; + request.url = '/v3/contactdb/recipients/{recipient_id}'; + it('should have the correct response code', () => { + return testRequest(request, 200); + }); +}); + +describe('test_contactdb_recipients__recipient_id__lists_get', () => { + const request = {}; + request.method = 'GET'; + request.url = '/v3/contactdb/recipients/{recipient_id}/lists'; + it('should have the correct response code', () => { + return testRequest(request, 200); + }); +}); + +describe('test_contactdb_reserved_fields_get', () => { + const request = {}; + request.method = 'GET'; + request.url = '/v3/contactdb/reserved_fields'; + it('should have the correct response code', () => { + return testRequest(request, 200); + }); +}); + +describe('test_contactdb_segments_post', () => { + const request = {}; + request.body = { + conditions: [ + { + and_or: '', + field: 'last_name', + operator: 'eq', + value: 'Miller', + }, + { + and_or: 'and', + field: 'last_clicked', + operator: 'gt', + value: '01/02/2015', + }, + { + and_or: 'or', + field: 'clicks.campaign_identifier', + operator: 'eq', + value: '513', + }, + ], + list_id: 4, + name: 'Last Name Miller', + }; + request.method = 'POST'; + request.url = '/v3/contactdb/segments'; + it('should have the correct response code', () => { + return testRequest(request, 200); + }); +}); + +describe('test_contactdb_segments_get', () => { + const request = {}; + request.method = 'GET'; + request.url = '/v3/contactdb/segments'; + it('should have the correct response code', () => { + return testRequest(request, 200); + }); +}); + +describe('test_contactdb_segments__segment_id__delete', () => { + const request = {}; + request.qs = { + delete_contacts: 'true', + }; + request.method = 'DELETE'; + request.url = '/v3/contactdb/segments/{segment_id}'; + xit('should have the correct response code', () => { + return testRequest(request, 204); + }); +}); + +describe('test_contactdb_segments__segment_id__patch', () => { + const request = {}; + request.body = { + conditions: [ + { + and_or: '', + field: 'last_name', + operator: 'eq', + value: 'Miller', + }, + ], + list_id: 5, + name: 'The Millers', + }; + request.qs = { + segment_id: 'test_string', + }; + request.method = 'PATCH'; + request.url = '/v3/contactdb/segments/{segment_id}'; + it('should have the correct response code', () => { + return testRequest(request, 200); + }); +}); + +describe('test_contactdb_segments__segment_id__get', () => { + const request = {}; + request.qs = { + segment_id: 1, + }; + request.method = 'GET'; + request.url = '/v3/contactdb/segments/{segment_id}'; + it('should have the correct response code', () => { + return testRequest(request, 200); + }); +}); + +describe('test_contactdb_segments__segment_id__recipients_get', () => { + const request = {}; + request.qs = { + page: 1, + page_size: 1, + }; + request.method = 'GET'; + request.url = '/v3/contactdb/segments/{segment_id}/recipients'; + it('should have the correct response code', () => { + return testRequest(request, 200); + }); +}); + +describe('test_contactdb_status_get', () => { + const request = {}; + request.method = 'GET'; + request.url = '/v3/contactdb/status'; + it('should have the correct response code', () => { + return testRequest(request, 200); + }); +}); + +describe('test_devices_stats_get', () => { + const request = {}; + request.qs = { + aggregated_by: 'day', + end_date: '2016-04-01', + limit: 1, + offset: 1, + start_date: '2016-01-01', + }; + request.method = 'GET'; + request.url = '/v3/devices/stats'; + it('should have the correct response code', () => { + return testRequest(request, 200); + }); +}); + +describe('test_geo_stats_get', () => { + const request = {}; + request.qs = { + aggregated_by: 'day', + country: 'US', + end_date: '2016-04-01', + limit: 1, + offset: 1, + start_date: '2016-01-01', + }; + request.method = 'GET'; + request.url = '/v3/geo/stats'; + it('should have the correct response code', () => { + return testRequest(request, 200); + }); +}); + +describe('test_ips_post', () => { + const request = {}; + request.body = { + count: 90323478, + subusers: [ + 'subuser1', + 'subuser2', + ], + user_can_send: true, + warmup: true, + }; + request.method = 'POST'; + request.url = '/v3/ips'; + it('should have the correct response code', () => { + return testRequest(request, 201); + }); +}); + +describe('test_ips_get', () => { + const request = {}; + request.qs = { + exclude_whitelabels: 'true', + ip: 'test_string', + limit: 1, + offset: 1, + sort_by_direction: 'asc', + subuser: 'test_string', + }; + request.method = 'GET'; + request.url = '/v3/ips'; + it('should have the correct response code', () => { + return testRequest(request, 200); + }); +}); + +describe('test_ips_assigned_get', () => { + const request = {}; + request.method = 'GET'; + request.url = '/v3/ips/assigned'; + it('should have the correct response code', () => { + return testRequest(request, 200); + }); +}); + +describe('test_ips_pools_post', () => { + const request = {}; + request.body = { + name: 'marketing', + }; + request.method = 'POST'; + request.url = '/v3/ips/pools'; + it('should have the correct response code', () => { + return testRequest(request, 200); + }); +}); + +describe('test_ips_pools_get', () => { + const request = {}; + request.method = 'GET'; + request.url = '/v3/ips/pools'; + it('should have the correct response code', () => { + return testRequest(request, 200); + }); +}); + +describe('test_ips_pools__pool_name__put', () => { + const request = {}; + request.body = { + name: 'new_pool_name', + }; + request.method = 'PUT'; + request.url = '/v3/ips/pools/{pool_name}'; + it('should have the correct response code', () => { + return testRequest(request, 200); + }); +}); + +describe('test_ips_pools__pool_name__delete', () => { + const request = {}; + request.method = 'DELETE'; + request.url = '/v3/ips/pools/{pool_name}'; + xit('should have the correct response code', () => { + return testRequest(request, 204); + }); +}); + +describe('test_ips_pools__pool_name__get', () => { + const request = {}; + request.method = 'GET'; + request.url = '/v3/ips/pools/{pool_name}'; + it('should have the correct response code', () => { + return testRequest(request, 200); + }); +}); + +describe('test_ips_pools__pool_name__ips_post', () => { + const request = {}; + request.body = { + ip: '0.0.0.0', + }; + request.method = 'POST'; + request.url = '/v3/ips/pools/{pool_name}/ips'; + it('should have the correct response code', () => { + return testRequest(request, 201); + }); +}); + +describe('test_ips_pools__pool_name__ips__ip__delete', () => { + const request = {}; + request.method = 'DELETE'; + request.url = '/v3/ips/pools/{pool_name}/ips/{ip}'; + xit('should have the correct response code', () => { + return testRequest(request, 204); + }); +}); + +describe('test_ips_remaining_get', () => { + const request = {}; + request.method = 'GET'; + request.url = '/v3/ips/remaining'; + it('should have the correct response code', () => { + return testRequest(request, 200); + }); +}); + +describe('test_ips_warmup_post', () => { + const request = {}; + request.body = { + ip: '0.0.0.0', + }; + request.method = 'POST'; + request.url = '/v3/ips/warmup'; + it('should have the correct response code', () => { + return testRequest(request, 200); + }); +}); + +describe('test_ips_warmup_get', () => { + const request = {}; + request.method = 'GET'; + request.url = '/v3/ips/warmup'; + it('should have the correct response code', () => { + return testRequest(request, 200); + }); +}); + +describe('test_ips_warmup__ip_address__delete', () => { + const request = {}; + request.method = 'DELETE'; + request.url = '/v3/ips/warmup/{ip_address}'; + xit('should have the correct response code', () => { + return testRequest(request, 204); + }); +}); + +describe('test_ips_warmup__ip_address__get', () => { + const request = {}; + request.method = 'GET'; + request.url = '/v3/ips/warmup/{ip_address}'; + it('should have the correct response code', () => { + return testRequest(request, 200); + }); +}); + +describe('test_ips__ip_address__get', () => { + const request = {}; + request.method = 'GET'; + request.url = '/v3/ips/{ip_address}'; + it('should have the correct response code', () => { + return testRequest(request, 200); + }); +}); + +describe('test_mail_batch_post', () => { + const request = {}; + request.method = 'POST'; + request.url = '/v3/mail/batch'; + it('should have the correct response code', () => { + return testRequest(request, 201); + }); +}); + +describe('test_mail_batch__batch_id__get', () => { + const request = {}; + request.method = 'GET'; + request.url = '/v3/mail/batch/{batch_id}'; + it('should have the correct response code', () => { + return testRequest(request, 200); + }); +}); + +describe('test_mail_send_post', () => { + const request = {}; + request.body = { + content: [ + { + type: 'text/html', + value: 'Hello, world!
', + }, + ], + from: { + email: 'sam.smith@example.com', + name: 'Sam Smith', + }, + personalizations: [ + { + subject: 'Hello, World!', + to: [ + { + email: 'john.doe@example.com', + name: 'John Doe', + }, + ], + }, + ], + reply_to: { + email: 'sam.smith@example.com', + name: 'Sam Smith', + }, + subject: 'Hello, World!', + }; + request.method = 'POST'; + request.url = '/v3/mail/send'; + it('should have the correct response code', () => { + return testRequest(request, 202); + }); +}); + +describe('test_mail_settings_get', () => { + const request = {}; + request.qs = { + limit: 1, + offset: 1, + }; + request.method = 'GET'; + request.url = '/v3/mail_settings'; + it('should have the correct response code', () => { + return testRequest(request, 200); + }); +}); + +describe('test_mail_settings_address_whitelist_patch', () => { + const request = {}; + request.body = { + enabled: true, + list: [ + 'email1@example.com', + 'example.com', + ], + }; + request.method = 'PATCH'; + request.url = '/v3/mail_settings/address_whitelist'; + it('should have the correct response code', () => { + return testRequest(request, 200); + }); +}); + +describe('test_mail_settings_address_whitelist_get', () => { + const request = {}; + request.method = 'GET'; + request.url = '/v3/mail_settings/address_whitelist'; + it('should have the correct response code', () => { + return testRequest(request, 200); + }); +}); + +describe('test_mail_settings_bcc_patch', () => { + const request = {}; + request.body = { + email: 'email@example.com', + enabled: false, + }; + request.method = 'PATCH'; + request.url = '/v3/mail_settings/bcc'; + it('should have the correct response code', () => { + return testRequest(request, 200); + }); +}); + +describe('test_mail_settings_bcc_get', () => { + const request = {}; + request.method = 'GET'; + request.url = '/v3/mail_settings/bcc'; + it('should have the correct response code', () => { + return testRequest(request, 200); + }); +}); + +describe('test_mail_settings_bounce_purge_patch', () => { + const request = {}; + request.body = { + enabled: true, + hard_bounces: 5, + soft_bounces: 5, + }; + request.method = 'PATCH'; + request.url = '/v3/mail_settings/bounce_purge'; + it('should have the correct response code', () => { + return testRequest(request, 200); + }); +}); + +describe('test_mail_settings_bounce_purge_get', () => { + const request = {}; + request.method = 'GET'; + request.url = '/v3/mail_settings/bounce_purge'; + it('should have the correct response code', () => { + return testRequest(request, 200); + }); +}); + +describe('test_mail_settings_footer_patch', () => { + const request = {}; + request.body = { + enabled: true, + html_content: '...', + plain_content: '...', + }; + request.method = 'PATCH'; + request.url = '/v3/mail_settings/footer'; + it('should have the correct response code', () => { + return testRequest(request, 200); + }); +}); + +describe('test_mail_settings_footer_get', () => { + const request = {}; + request.method = 'GET'; + request.url = '/v3/mail_settings/footer'; + it('should have the correct response code', () => { + return testRequest(request, 200); + }); +}); + +describe('test_mail_settings_forward_bounce_patch', () => { + const request = {}; + request.body = { + email: 'example@example.com', + enabled: true, + }; + request.method = 'PATCH'; + request.url = '/v3/mail_settings/forward_bounce'; + it('should have the correct response code', () => { + return testRequest(request, 200); + }); +}); + +describe('test_mail_settings_forward_bounce_get', () => { + const request = {}; + request.method = 'GET'; + request.url = '/v3/mail_settings/forward_bounce'; + it('should have the correct response code', () => { + return testRequest(request, 200); + }); +}); + +describe('test_mail_settings_forward_spam_patch', () => { + const request = {}; + request.body = { + email: '', + enabled: false, + }; + request.method = 'PATCH'; + request.url = '/v3/mail_settings/forward_spam'; + it('should have the correct response code', () => { + return testRequest(request, 200); + }); +}); + +describe('test_mail_settings_forward_spam_get', () => { + const request = {}; + request.method = 'GET'; + request.url = '/v3/mail_settings/forward_spam'; + it('should have the correct response code', () => { + return testRequest(request, 200); + }); +}); + +describe('test_mail_settings_plain_content_patch', () => { + const request = {}; + request.body = { + enabled: false, + }; + request.method = 'PATCH'; + request.url = '/v3/mail_settings/plain_content'; + it('should have the correct response code', () => { + return testRequest(request, 200); + }); +}); + +describe('test_mail_settings_plain_content_get', () => { + const request = {}; + request.method = 'GET'; + request.url = '/v3/mail_settings/plain_content'; + it('should have the correct response code', () => { + return testRequest(request, 200); + }); +}); + +describe('test_mail_settings_spam_check_patch', () => { + const request = {}; + request.body = { + enabled: true, + max_score: 5, + url: 'url', + }; + request.method = 'PATCH'; + request.url = '/v3/mail_settings/spam_check'; + it('should have the correct response code', () => { + return testRequest(request, 200); + }); +}); + +describe('test_mail_settings_spam_check_get', () => { + const request = {}; + request.method = 'GET'; + request.url = '/v3/mail_settings/spam_check'; + it('should have the correct response code', () => { + return testRequest(request, 200); + }); +}); + +describe('test_mail_settings_template_patch', () => { + const request = {}; + request.body = { + enabled: true, + html_content: '<% body %>', + }; + request.method = 'PATCH'; + request.url = '/v3/mail_settings/template'; + it('should have the correct response code', () => { + return testRequest(request, 200); + }); +}); + +describe('test_mail_settings_template_get', () => { + const request = {}; + request.method = 'GET'; + request.url = '/v3/mail_settings/template'; + it('should have the correct response code', () => { + return testRequest(request, 200); + }); +}); + +describe('test_mailbox_providers_stats_get', () => { + const request = {}; + request.qs = { + aggregated_by: 'day', + end_date: '2016-04-01', + limit: 1, + mailbox_providers: 'test_string', + offset: 1, + start_date: '2016-01-01', + }; + request.method = 'GET'; + request.url = '/v3/mailbox_providers/stats'; + it('should have the correct response code', () => { + return testRequest(request, 200); + }); +}); + +describe('test_partner_settings_get', () => { + const request = {}; + request.qs = { + limit: 1, + offset: 1, + }; + request.method = 'GET'; + request.url = '/v3/partner_settings'; + it('should have the correct response code', () => { + return testRequest(request, 200); + }); +}); + +describe('test_partner_settings_new_relic_patch', () => { + const request = {}; + request.body = { + enable_subuser_statistics: true, + enabled: true, + license_key: '', + }; + request.method = 'PATCH'; + request.url = '/v3/partner_settings/new_relic'; + it('should have the correct response code', () => { + return testRequest(request, 200); + }); +}); + +describe('test_partner_settings_new_relic_get', () => { + const request = {}; + request.method = 'GET'; + request.url = '/v3/partner_settings/new_relic'; + it('should have the correct response code', () => { + return testRequest(request, 200); + }); +}); + +describe('test_scopes_get', () => { + const request = {}; + request.method = 'GET'; + request.url = '/v3/scopes'; + it('should have the correct response code', () => { + return testRequest(request, 200); + }); +}); + +describe('test_scopes_requests_get', () => { + const request = {}; + request.qs = { + limit: 1, + offset: 1, + }; + request.method = 'GET'; + request.url = '/v3/scopes/requests'; + it('should have the correct response code', () => { + return testRequest(request, 200); + }); +}); + +describe('test_scopes_requests__request_id__delete', () => { + const request = {}; + request.method = 'DELETE'; + request.url = '/v3/scopes/requests/{request_id}'; + xit('should have the correct response code', () => { + return testRequest(request, 204); + }); +}); + +describe('test_scopes_requests__request_id__approve_patch', () => { + const request = {}; + request.method = 'PATCH'; + request.url = '/v3/scopes/requests/{request_id}/approve'; + it('should have the correct response code', () => { + return testRequest(request, 200); + }); +}); + +describe('test_senders_post', () => { + const request = {}; + request.body = { + address: '123 Elm St.', + address_2: 'Apt. 456', + city: 'Denver', + country: 'United States', + from: { + email: 'from@example.com', + name: 'Example INC', + }, + nickname: 'My Sender ID', + reply_to: { + email: 'replyto@example.com', + name: 'Example INC', + }, + state: 'Colorado', + zip: '80202', + }; + request.method = 'POST'; + request.url = '/v3/senders'; + it('should have the correct response code', () => { + return testRequest(request, 201); + }); +}); + +describe('test_senders_get', () => { + const request = {}; + request.method = 'GET'; + request.url = '/v3/senders'; + it('should have the correct response code', () => { + return testRequest(request, 200); + }); +}); + +describe('test_senders__sender_id__get', () => { + const request = {}; + request.method = 'GET'; + request.url = '/v3/senders/{sender_id}'; + it('should have the correct response code', () => { + return testRequest(request, 200); + }); +}); + +describe('test_senders__sender_id__delete', () => { + const request = {}; + request.method = 'DELETE'; + request.url = '/v3/senders/{sender_id}'; + xit('should have the correct response code', () => { + return testRequest(request, 204); + }); +}); + +describe('test_senders__sender_id__patch', () => { + const request = {}; + request.body = { + address: '123 Elm St.', + address_2: 'Apt. 456', + city: 'Denver', + country: 'United States', + from: { + email: 'from@example.com', + name: 'Example INC', + }, + nickname: 'My Sender ID', + reply_to: { + email: 'replyto@example.com', + name: 'Example INC', + }, + state: 'Colorado', + zip: '80202', + }; + request.method = 'PATCH'; + request.url = '/v3/senders/{sender_id}'; + it('should have the correct response code', () => { + return testRequest(request, 200); + }); +}); + +describe('test_senders__sender_id__resend_verification_post', () => { + const request = {}; + request.method = 'POST'; + request.url = '/v3/senders/{sender_id}/resend_verification'; + xit('should have the correct response code', () => { + return testRequest(request, 204); + }); +}); + +describe('test_stats_get', () => { + const request = {}; + request.qs = { + aggregated_by: 'day', + end_date: '2016-04-01', + limit: 1, + offset: 1, + start_date: '2016-01-01', + }; + request.method = 'GET'; + request.url = '/v3/stats'; + it('should have the correct response code', () => { + return testRequest(request, 200); + }); +}); + +describe('test_subusers_post', () => { + const request = {}; + request.body = { + email: 'John@example.com', + ips: [ + '1.1.1.1', + '2.2.2.2', + ], + password: 'johns_password', + username: 'John@example.com', + }; + request.method = 'POST'; + request.url = '/v3/subusers'; + it('should have the correct response code', () => { + return testRequest(request, 200); + }); +}); + +describe('test_subusers_get', () => { + const request = {}; + request.qs = { + limit: 1, + offset: 1, + username: 'test_string', + }; + request.method = 'GET'; + request.url = '/v3/subusers'; + it('should have the correct response code', () => { + return testRequest(request, 200); + }); +}); + +describe('test_subusers_reputations_get', () => { + const request = {}; + request.qs = { + usernames: 'test_string', + }; + request.method = 'GET'; + request.url = '/v3/subusers/reputations'; + it('should have the correct response code', () => { + return testRequest(request, 200); + }); +}); + +describe('test_subusers_stats_get', () => { + const request = {}; + request.qs = { + aggregated_by: 'day', + end_date: '2016-04-01', + limit: 1, + offset: 1, + start_date: '2016-01-01', + subusers: 'test_string', + }; + request.method = 'GET'; + request.url = '/v3/subusers/stats'; + it('should have the correct response code', () => { + return testRequest(request, 200); + }); +}); + +describe('test_subusers_stats_monthly_get', () => { + const request = {}; + request.qs = { + date: 'test_string', + limit: 1, + offset: 1, + sort_by_direction: 'asc', + sort_by_metric: 'test_string', + subuser: 'test_string', + }; + request.method = 'GET'; + request.url = '/v3/subusers/stats/monthly'; + it('should have the correct response code', () => { + return testRequest(request, 200); + }); +}); + +describe('test_subusers_stats_sums_get', () => { + const request = {}; + request.qs = { + aggregated_by: 'day', + end_date: '2016-04-01', + limit: 1, + offset: 1, + sort_by_direction: 'asc', + sort_by_metric: 'test_string', + start_date: '2016-01-01', + }; + request.method = 'GET'; + request.url = '/v3/subusers/stats/sums'; + it('should have the correct response code', () => { + return testRequest(request, 200); + }); +}); + +describe('test_subusers__subuser_name__delete', () => { + const request = {}; + request.method = 'DELETE'; + request.url = '/v3/subusers/{subuser_name}'; + xit('should have the correct response code', () => { + return testRequest(request, 204); + }); +}); + +describe('test_subusers__subuser_name__patch', () => { + const request = {}; + request.body = { + disabled: false, + }; + request.method = 'PATCH'; + request.url = '/v3/subusers/{subuser_name}'; + xit('should have the correct response code', () => { + return testRequest(request, 204); + }); +}); + +describe('test_subusers__subuser_name__ips_put', () => { + const request = {}; + request.body = [ + '127.0.0.1', + ]; + request.method = 'PUT'; + request.url = '/v3/subusers/{subuser_name}/ips'; + it('should have the correct response code', () => { + return testRequest(request, 200); + }); +}); + +describe('test_subusers__subuser_name__monitor_put', () => { + const request = {}; + request.body = { + email: 'example@example.com', + frequency: 500, + }; + request.method = 'PUT'; + request.url = '/v3/subusers/{subuser_name}/monitor'; + it('should have the correct response code', () => { + return testRequest(request, 200); + }); +}); + +describe('test_subusers__subuser_name__monitor_post', () => { + const request = {}; + request.body = { + email: 'example@example.com', + frequency: 50000, + }; + request.method = 'POST'; + request.url = '/v3/subusers/{subuser_name}/monitor'; + it('should have the correct response code', () => { + return testRequest(request, 200); + }); +}); + +describe('test_subusers__subuser_name__monitor_delete', () => { + const request = {}; + request.method = 'DELETE'; + request.url = '/v3/subusers/{subuser_name}/monitor'; + xit('should have the correct response code', () => { + return testRequest(request, 204); + }); +}); + +describe('test_subusers__subuser_name__monitor_get', () => { + const request = {}; + request.method = 'GET'; + request.url = '/v3/subusers/{subuser_name}/monitor'; + it('should have the correct response code', () => { + return testRequest(request, 200); + }); +}); + +describe('test_subusers__subuser_name__stats_monthly_get', () => { + const request = {}; + request.qs = { + date: 'test_string', + limit: 1, + offset: 1, + sort_by_direction: 'asc', + sort_by_metric: 'test_string', + }; + request.method = 'GET'; + request.url = '/v3/subusers/{subuser_name}/stats/monthly'; + it('should have the correct response code', () => { + return testRequest(request, 200); + }); +}); + +describe('test_suppression_blocks_delete', () => { + const request = {}; + request.body = { + delete_all: false, + emails: [ + 'example1@example.com', + 'example2@example.com', + ], + }; + request.method = 'DELETE'; + request.url = '/v3/suppression/blocks'; + xit('should have the correct response code', () => { + return testRequest(request, 204); + }); +}); + +describe('test_suppression_blocks_get', () => { + const request = {}; + request.qs = { + end_time: 1, + limit: 1, + offset: 1, + start_time: 1, + }; + request.method = 'GET'; + request.url = '/v3/suppression/blocks'; + it('should have the correct response code', () => { + return testRequest(request, 200); + }); +}); + +describe('test_suppression_blocks__email__delete', () => { + const request = {}; + request.method = 'DELETE'; + request.url = '/v3/suppression/blocks/{email}'; + xit('should have the correct response code', () => { + return testRequest(request, 204); + }); +}); + +describe('test_suppression_blocks__email__get', () => { + const request = {}; + request.method = 'GET'; + request.url = '/v3/suppression/blocks/{email}'; + it('should have the correct response code', () => { + return testRequest(request, 200); + }); +}); + +describe('test_suppression_bounces_delete', () => { + const request = {}; + request.body = { + delete_all: true, + emails: [ + 'example@example.com', + 'example2@example.com', + ], + }; + request.method = 'DELETE'; + request.url = '/v3/suppression/bounces'; + xit('should have the correct response code', () => { + return testRequest(request, 204); + }); +}); + +describe('test_suppression_bounces_get', () => { + const request = {}; + request.qs = { + end_time: 1, + start_time: 1, + }; + request.method = 'GET'; + request.url = '/v3/suppression/bounces'; + it('should have the correct response code', () => { + return testRequest(request, 200); + }); +}); + +describe('test_suppression_bounces__email__delete', () => { + const request = {}; + request.qs = { + email_address: 'example@example.com', + }; + request.method = 'DELETE'; + request.url = '/v3/suppression/bounces/{email}'; + xit('should have the correct response code', () => { + return testRequest(request, 204); + }); +}); + +describe('test_suppression_bounces__email__get', () => { + const request = {}; + request.method = 'GET'; + request.url = '/v3/suppression/bounces/{email}'; + it('should have the correct response code', () => { + return testRequest(request, 200); + }); +}); + +describe('test_suppression_invalid_emails_delete', () => { + const request = {}; + request.body = { + delete_all: false, + emails: [ + 'example1@example.com', + 'example2@example.com', + ], + }; + request.method = 'DELETE'; + request.url = '/v3/suppression/invalid_emails'; + xit('should have the correct response code', () => { + return testRequest(request, 204); + }); +}); + +describe('test_suppression_invalid_emails_get', () => { + const request = {}; + request.qs = { + end_time: 1, + limit: 1, + offset: 1, + start_time: 1, + }; + request.method = 'GET'; + request.url = '/v3/suppression/invalid_emails'; + it('should have the correct response code', () => { + return testRequest(request, 200); + }); +}); + +describe('test_suppression_invalid_emails__email__delete', () => { + const request = {}; + request.method = 'DELETE'; + request.url = '/v3/suppression/invalid_emails/{email}'; + xit('should have the correct response code', () => { + return testRequest(request, 204); + }); +}); + +describe('test_suppression_invalid_emails__email__get', () => { + const request = {}; + request.method = 'GET'; + request.url = '/v3/suppression/invalid_emails/{email}'; + it('should have the correct response code', () => { + return testRequest(request, 200); + }); +}); + +describe('test_suppression_spam_reports_delete', () => { + const request = {}; + request.body = { + delete_all: false, + emails: [ + 'example1@example.com', + 'example2@example.com', + ], + }; + request.method = 'DELETE'; + request.url = '/v3/suppression/spam_reports'; + xit('should have the correct response code', () => { + return testRequest(request, 204); + }); +}); + +describe('test_suppression_spam_reports_get', () => { + const request = {}; + request.qs = { + end_time: 1, + limit: 1, + offset: 1, + start_time: 1, + }; + request.method = 'GET'; + request.url = '/v3/suppression/spam_reports'; + it('should have the correct response code', () => { + return testRequest(request, 200); + }); +}); + +describe('test_suppression_spam_reports__email__delete', () => { + const request = {}; + request.method = 'DELETE'; + request.url = '/v3/suppression/spam_reports/{email}'; + xit('should have the correct response code', () => { + return testRequest(request, 204); + }); +}); + +describe('test_suppression_spam_reports__email__get', () => { + const request = {}; + request.method = 'GET'; + request.url = '/v3/suppression/spam_reports/{email}'; + it('should have the correct response code', () => { + return testRequest(request, 200); + }); +}); + +describe('test_suppression_unsubscribes_get', () => { + const request = {}; + request.qs = { + end_time: 1, + limit: 1, + offset: 1, + start_time: 1, + }; + request.method = 'GET'; + request.url = '/v3/suppression/unsubscribes'; + it('should have the correct response code', () => { + return testRequest(request, 200); + }); +}); + +describe('test_teammates_post', () => { + const request = {}; + request.body = { + email: 'teammate1@example.com', + is_admin: false, + scopes: [ + 'user.profile.read', + 'user.profile.update', + ], + }; + request.method = 'POST'; + request.url = '/v3/teammates'; + it('should have the correct response code', () => { + return testRequest(request, 201); + }); +}); + +describe('test_teammates_get', () => { + const request = {}; + request.qs = { + limit: 1, + offset: 1, + }; + request.method = 'GET'; + request.url = '/v3/teammates'; + it('should have the correct response code', () => { + return testRequest(request, 200); + }); +}); + +describe('test_teammates_pending_get', () => { + const request = {}; + request.method = 'GET'; + request.url = '/v3/teammates/pending'; + it('should have the correct response code', () => { + return testRequest(request, 200); + }); +}); + +describe('test_teammates_pending__token__delete', () => { + const request = {}; + request.method = 'DELETE'; + request.url = '/v3/teammates/pending/{token}'; + xit('should have the correct response code', () => { + return testRequest(request, 204); + }); +}); + +describe('test_teammates_pending__token__resend_post', () => { + const request = {}; + request.method = 'POST'; + request.url = '/v3/teammates/pending/{token}/resend'; + it('should have the correct response code', () => { + return testRequest(request, 200); + }); +}); + +describe('test_teammates__username__delete', () => { + const request = {}; + request.method = 'DELETE'; + request.url = '/v3/teammates/{username}'; + xit('should have the correct response code', () => { + return testRequest(request, 204); + }); +}); + +describe('test_teammates__username__patch', () => { + const request = {}; + request.body = { + is_admin: false, + scopes: [ + 'user.profile.read', + 'user.profile.edit', + ], + }; + request.method = 'PATCH'; + request.url = '/v3/teammates/{username}'; + it('should have the correct response code', () => { + return testRequest(request, 200); + }); +}); + +describe('test_teammates__username__get', () => { + const request = {}; + request.method = 'GET'; + request.url = '/v3/teammates/{username}'; + it('should have the correct response code', () => { + return testRequest(request, 200); + }); +}); + +describe('test_templates_post', () => { + const request = {}; + request.body = { + name: 'example_name', + }; + request.method = 'POST'; + request.url = '/v3/templates'; + it('should have the correct response code', () => { + return testRequest(request, 201); + }); +}); + +describe('test_templates_get', () => { + const request = {}; + request.method = 'GET'; + request.url = '/v3/templates'; + it('should have the correct response code', () => { + return testRequest(request, 200); + }); +}); + +describe('test_templates__template_id__delete', () => { + const request = {}; + request.method = 'DELETE'; + request.url = '/v3/templates/{template_id}'; + xit('should have the correct response code', () => { + return testRequest(request, 204); + }); +}); + +describe('test_templates__template_id__patch', () => { + const request = {}; + request.body = { + name: 'new_example_name', + }; + request.method = 'PATCH'; + request.url = '/v3/templates/{template_id}'; + it('should have the correct response code', () => { + return testRequest(request, 200); + }); +}); + +describe('test_templates__template_id__get', () => { + const request = {}; + request.method = 'GET'; + request.url = '/v3/templates/{template_id}'; + it('should have the correct response code', () => { + return testRequest(request, 200); + }); +}); + +describe('test_templates__template_id__versions_post', () => { + const request = {}; + request.body = { + active: 1, + html_content: '<%body%>', + name: 'example_version_name', + plain_content: '<%body%>', + subject: '<%subject%>', + template_id: 'ddb96bbc-9b92-425e-8979-99464621b543', + }; + request.method = 'POST'; + request.url = '/v3/templates/{template_id}/versions'; + it('should have the correct response code', () => { + return testRequest(request, 201); + }); +}); + +describe('test_templates__template_id__versions__version_id__delete', () => { + const request = {}; + request.method = 'DELETE'; + request.url = '/v3/templates/{template_id}/versions/{version_id}'; + xit('should have the correct response code', () => { + return testRequest(request, 204); + }); +}); + +describe('test_templates__template_id__versions__version_id__patch', () => { + const request = {}; + request.body = { + active: 1, + html_content: '<%body%>', + name: 'updated_example_name', + plain_content: '<%body%>', + subject: '<%subject%>', + }; + request.method = 'PATCH'; + request.url = '/v3/templates/{template_id}/versions/{version_id}'; + it('should have the correct response code', () => { + return testRequest(request, 200); + }); +}); + +describe('test_templates__template_id__versions__version_id__get', () => { + const request = {}; + request.method = 'GET'; + request.url = '/v3/templates/{template_id}/versions/{version_id}'; + it('should have the correct response code', () => { + return testRequest(request, 200); + }); +}); + +describe('test_templates__template_id__versions__version_id__activate_post', () => { + const request = {}; + request.method = 'POST'; + request.url = '/v3/templates/{template_id}/versions/{version_id}/activate'; + it('should have the correct response code', () => { + return testRequest(request, 200); + }); +}); + +describe('test_tracking_settings_get', () => { + const request = {}; + request.qs = { + limit: 1, + offset: 1, + }; + request.method = 'GET'; + request.url = '/v3/tracking_settings'; + it('should have the correct response code', () => { + return testRequest(request, 200); + }); +}); + +describe('test_tracking_settings_click_patch', () => { + const request = {}; + request.body = { + enabled: true, + }; + request.method = 'PATCH'; + request.url = '/v3/tracking_settings/click'; + it('should have the correct response code', () => { + return testRequest(request, 200); + }); +}); + +describe('test_tracking_settings_click_get', () => { + const request = {}; + request.method = 'GET'; + request.url = '/v3/tracking_settings/click'; + it('should have the correct response code', () => { + return testRequest(request, 200); + }); +}); + +describe('test_tracking_settings_google_analytics_patch', () => { + const request = {}; + request.body = { + enabled: true, + utm_campaign: 'website', + utm_content: '', + utm_medium: 'email', + utm_source: 'sendgrid.com', + utm_term: '', + }; + request.method = 'PATCH'; + request.url = '/v3/tracking_settings/google_analytics'; + it('should have the correct response code', () => { + return testRequest(request, 200); + }); +}); + +describe('test_tracking_settings_google_analytics_get', () => { + const request = {}; + request.method = 'GET'; + request.url = '/v3/tracking_settings/google_analytics'; + it('should have the correct response code', () => { + return testRequest(request, 200); + }); +}); + +describe('test_tracking_settings_open_patch', () => { + const request = {}; + request.body = { + enabled: true, + }; + request.method = 'PATCH'; + request.url = '/v3/tracking_settings/open'; + it('should have the correct response code', () => { + return testRequest(request, 200); + }); +}); + +describe('test_tracking_settings_open_get', () => { + const request = {}; + request.method = 'GET'; + request.url = '/v3/tracking_settings/open'; + it('should have the correct response code', () => { + return testRequest(request, 200); + }); +}); + +describe('test_tracking_settings_subscription_patch', () => { + const request = {}; + request.body = { + enabled: true, + html_content: 'html content', + landing: 'landing page html', + plain_content: 'text content', + replace: 'replacement tag', + url: 'url', + }; + request.method = 'PATCH'; + request.url = '/v3/tracking_settings/subscription'; + it('should have the correct response code', () => { + return testRequest(request, 200); + }); +}); + +describe('test_tracking_settings_subscription_get', () => { + const request = {}; + request.method = 'GET'; + request.url = '/v3/tracking_settings/subscription'; + it('should have the correct response code', () => { + return testRequest(request, 200); + }); +}); + +describe('test_user_account_get', () => { + const request = {}; + request.method = 'GET'; + request.url = '/v3/user/account'; + it('should have the correct response code', () => { + return testRequest(request, 200); + }); +}); + +describe('test_user_credits_get', () => { + const request = {}; + request.method = 'GET'; + request.url = '/v3/user/credits'; + it('should have the correct response code', () => { + return testRequest(request, 200); + }); +}); + +describe('test_user_email_put', () => { + const request = {}; + request.body = { + email: 'example@example.com', + }; + request.method = 'PUT'; + request.url = '/v3/user/email'; + it('should have the correct response code', () => { + return testRequest(request, 200); + }); +}); + +describe('test_user_email_get', () => { + const request = {}; + request.method = 'GET'; + request.url = '/v3/user/email'; + it('should have the correct response code', () => { + return testRequest(request, 200); + }); +}); + +describe('test_user_password_put', () => { + const request = {}; + request.body = { + new_password: 'new_password', + old_password: 'old_password', + }; + request.method = 'PUT'; + request.url = '/v3/user/password'; + it('should have the correct response code', () => { + return testRequest(request, 200); + }); +}); + +describe('test_user_profile_patch', () => { + const request = {}; + request.body = { + city: 'Orange', + first_name: 'Example', + last_name: 'User', + }; + request.method = 'PATCH'; + request.url = '/v3/user/profile'; + it('should have the correct response code', () => { + return testRequest(request, 200); + }); +}); + +describe('test_user_profile_get', () => { + const request = {}; + request.method = 'GET'; + request.url = '/v3/user/profile'; + it('should have the correct response code', () => { + return testRequest(request, 200); + }); +}); + +describe('test_user_scheduled_sends_post', () => { + const request = {}; + request.body = { + batch_id: 'YOUR_BATCH_ID', + status: 'pause', + }; + request.method = 'POST'; + request.url = '/v3/user/scheduled_sends'; + it('should have the correct response code', () => { + return testRequest(request, 201); + }); +}); + +describe('test_user_scheduled_sends_get', () => { + const request = {}; + request.method = 'GET'; + request.url = '/v3/user/scheduled_sends'; + it('should have the correct response code', () => { + return testRequest(request, 200); + }); +}); + +describe('test_user_scheduled_sends__batch_id__delete', () => { + const request = {}; + request.method = 'DELETE'; + request.url = '/v3/user/scheduled_sends/{batch_id}'; + xit('should have the correct response code', () => { + return testRequest(request, 204); + }); +}); + +describe('test_user_scheduled_sends__batch_id__patch', () => { + const request = {}; + request.body = { + status: 'pause', + }; + request.method = 'PATCH'; + request.url = '/v3/user/scheduled_sends/{batch_id}'; + xit('should have the correct response code', () => { + return testRequest(request, 204); + }); +}); + +describe('test_user_scheduled_sends__batch_id__get', () => { + const request = {}; + request.method = 'GET'; + request.url = '/v3/user/scheduled_sends/{batch_id}'; + it('should have the correct response code', () => { + return testRequest(request, 200); + }); +}); + +describe('test_user_settings_enforced_tls_patch', () => { + const request = {}; + request.body = { + require_tls: true, + require_valid_cert: false, + }; + request.method = 'PATCH'; + request.url = '/v3/user/settings/enforced_tls'; + it('should have the correct response code', () => { + return testRequest(request, 200); + }); +}); + +describe('test_user_settings_enforced_tls_get', () => { + const request = {}; + request.method = 'GET'; + request.url = '/v3/user/settings/enforced_tls'; + it('should have the correct response code', () => { + return testRequest(request, 200); + }); +}); + +describe('test_user_username_put', () => { + const request = {}; + request.body = { + username: 'test_username', + }; + request.method = 'PUT'; + request.url = '/v3/user/username'; + it('should have the correct response code', () => { + return testRequest(request, 200); + }); +}); + +describe('test_user_username_get', () => { + const request = {}; + request.method = 'GET'; + request.url = '/v3/user/username'; + it('should have the correct response code', () => { + return testRequest(request, 200); + }); +}); + +describe('test_user_webhooks_event_settings_patch', () => { + const request = {}; + request.body = { + bounce: true, + click: true, + deferred: true, + delivered: true, + dropped: true, + enabled: true, + group_resubscribe: true, + group_unsubscribe: true, + open: true, + processed: true, + spam_report: true, + unsubscribe: true, + url: 'url', + }; + request.method = 'PATCH'; + request.url = '/v3/user/webhooks/event/settings'; + it('should have the correct response code', () => { + return testRequest(request, 200); + }); +}); + +describe('test_user_webhooks_event_settings_get', () => { + const request = {}; + request.method = 'GET'; + request.url = '/v3/user/webhooks/event/settings'; + it('should have the correct response code', () => { + return testRequest(request, 200); + }); +}); + +describe('test_user_webhooks_event_test_post', () => { + const request = {}; + request.body = { + url: 'url', + }; + request.method = 'POST'; + request.url = '/v3/user/webhooks/event/test'; + xit('should have the correct response code', () => { + return testRequest(request, 204); + }); +}); + +describe('test_user_webhooks_parse_settings_post', () => { + const request = {}; + request.body = { + hostname: 'myhostname.com', + send_raw: false, + spam_check: true, + url: 'http://email.myhosthame.com', + }; + request.method = 'POST'; + request.url = '/v3/user/webhooks/parse/settings'; + it('should have the correct response code', () => { + return testRequest(request, 201); + }); +}); + +describe('test_user_webhooks_parse_settings_get', () => { + const request = {}; + request.method = 'GET'; + request.url = '/v3/user/webhooks/parse/settings'; + it('should have the correct response code', () => { + return testRequest(request, 200); + }); +}); + +describe('test_user_webhooks_parse_settings__hostname__delete', () => { + const request = {}; + request.method = 'DELETE'; + request.url = '/v3/user/webhooks/parse/settings/{hostname}'; + xit('should have the correct response code', () => { + return testRequest(request, 204); + }); +}); + +describe('test_user_webhooks_parse_settings__hostname__patch', () => { + const request = {}; + request.body = { + send_raw: true, + spam_check: false, + url: 'http://newdomain.com/parse', + }; + request.method = 'PATCH'; + request.url = '/v3/user/webhooks/parse/settings/{hostname}'; + it('should have the correct response code', () => { + return testRequest(request, 200); + }); +}); + +describe('test_user_webhooks_parse_settings__hostname__get', () => { + const request = {}; + request.method = 'GET'; + request.url = '/v3/user/webhooks/parse/settings/{hostname}'; + it('should have the correct response code', () => { + return testRequest(request, 200); + }); +}); + +describe('test_user_webhooks_parse_stats_get', () => { + const request = {}; + request.qs = { + aggregated_by: 'day', + end_date: '2016-04-01', + limit: 'test_string', + offset: 'test_string', + start_date: '2016-01-01', + }; + request.method = 'GET'; + request.url = '/v3/user/webhooks/parse/stats'; + it('should have the correct response code', () => { + return testRequest(request, 200); + }); +}); + +describe('test_whitelabel_domains_post', () => { + const request = {}; + request.body = { + automatic_security: false, + custom_spf: true, + default: true, + domain: 'example.com', + ips: [ + '192.168.1.1', + '192.168.1.2', + ], + subdomain: 'news', + username: 'john@example.com', + }; + request.method = 'POST'; + request.url = '/v3/whitelabel/domains'; + it('should have the correct response code', () => { + return testRequest(request, 201); + }); +}); + +describe('test_whitelabel_domains_get', () => { + const request = {}; + request.qs = { + domain: 'test_string', + exclude_subusers: 'true', + limit: 1, + offset: 1, + username: 'test_string', + }; + request.method = 'GET'; + request.url = '/v3/whitelabel/domains'; + it('should have the correct response code', () => { + return testRequest(request, 200); + }); +}); + +describe('test_whitelabel_domains_default_get', () => { + const request = {}; + request.method = 'GET'; + request.url = '/v3/whitelabel/domains/default'; + it('should have the correct response code', () => { + return testRequest(request, 200); + }); +}); + +describe('test_whitelabel_domains_subuser_delete', () => { + const request = {}; + request.method = 'DELETE'; + request.url = '/v3/whitelabel/domains/subuser'; + xit('should have the correct response code', () => { + return testRequest(request, 204); + }); +}); + +describe('test_whitelabel_domains_subuser_get', () => { + const request = {}; + request.method = 'GET'; + request.url = '/v3/whitelabel/domains/subuser'; + it('should have the correct response code', () => { + return testRequest(request, 200); + }); +}); + +describe('test_whitelabel_domains__domain_id__delete', () => { + const request = {}; + request.method = 'DELETE'; + request.url = '/v3/whitelabel/domains/{domain_id}'; + xit('should have the correct response code', () => { + return testRequest(request, 204); + }); +}); + +describe('test_whitelabel_domains__domain_id__patch', () => { + const request = {}; + request.body = { + custom_spf: true, + default: false, + }; + request.method = 'PATCH'; + request.url = '/v3/whitelabel/domains/{domain_id}'; + it('should have the correct response code', () => { + return testRequest(request, 200); + }); +}); + +describe('test_whitelabel_domains__domain_id__get', () => { + const request = {}; + request.method = 'GET'; + request.url = '/v3/whitelabel/domains/{domain_id}'; + it('should have the correct response code', () => { + return testRequest(request, 200); + }); +}); + +describe('test_whitelabel_domains__domain_id__subuser_post', () => { + const request = {}; + request.body = { + username: 'jane@example.com', + }; + request.method = 'POST'; + request.url = '/v3/whitelabel/domains/{domain_id}/subuser'; + it('should have the correct response code', () => { + return testRequest(request, 201); + }); +}); + +describe('test_whitelabel_domains__id__ips_post', () => { + const request = {}; + request.body = { + ip: '192.168.0.1', + }; + request.method = 'POST'; + request.url = '/v3/whitelabel/domains/{id}/ips'; + it('should have the correct response code', () => { + return testRequest(request, 200); + }); +}); + +describe('test_whitelabel_domains__id__ips__ip__delete', () => { + const request = {}; + request.method = 'DELETE'; + request.url = '/v3/whitelabel/domains/{id}/ips/{ip}'; + it('should have the correct response code', () => { + return testRequest(request, 200); + }); +}); + +describe('test_whitelabel_domains__id__validate_post', () => { + const request = {}; + request.method = 'POST'; + request.url = '/v3/whitelabel/domains/{id}/validate'; + it('should have the correct response code', () => { + return testRequest(request, 200); + }); +}); + +describe('test_whitelabel_ips_post', () => { + const request = {}; + request.body = { + domain: 'example.com', + ip: '192.168.1.1', + subdomain: 'email', + }; + request.method = 'POST'; + request.url = '/v3/whitelabel/ips'; + it('should have the correct response code', () => { + return testRequest(request, 201); + }); +}); + +describe('test_whitelabel_ips_get', () => { + const request = {}; + request.qs = { + ip: 'test_string', + limit: 1, + offset: 1, + }; + request.method = 'GET'; + request.url = '/v3/whitelabel/ips'; + it('should have the correct response code', () => { + return testRequest(request, 200); + }); +}); + +describe('test_whitelabel_ips__id__delete', () => { + const request = {}; + request.method = 'DELETE'; + request.url = '/v3/whitelabel/ips/{id}'; + xit('should have the correct response code', () => { + return testRequest(request, 204); + }); +}); + +describe('test_whitelabel_ips__id__get', () => { + const request = {}; + request.method = 'GET'; + request.url = '/v3/whitelabel/ips/{id}'; + it('should have the correct response code', () => { + return testRequest(request, 200); + }); +}); + +describe('test_whitelabel_ips__id__validate_post', () => { + const request = {}; + request.method = 'POST'; + request.url = '/v3/whitelabel/ips/{id}/validate'; + it('should have the correct response code', () => { + return testRequest(request, 200); + }); +}); + +describe('test_whitelabel_links_post', () => { + const request = {}; + request.body = { + default: true, + domain: 'example.com', + subdomain: 'mail', + }; + request.qs = { + limit: 1, + offset: 1, + }; + request.method = 'POST'; + request.url = '/v3/whitelabel/links'; + it('should have the correct response code', () => { + return testRequest(request, 201); + }); +}); + +describe('test_whitelabel_links_get', () => { + const request = {}; + request.qs = { + limit: 1, + }; + request.method = 'GET'; + request.url = '/v3/whitelabel/links'; + it('should have the correct response code', () => { + return testRequest(request, 200); + }); +}); + +describe('test_whitelabel_links_default_get', () => { + const request = {}; + request.qs = { + domain: 'test_string', + }; + request.method = 'GET'; + request.url = '/v3/whitelabel/links/default'; + it('should have the correct response code', () => { + return testRequest(request, 200); + }); +}); + +describe('test_whitelabel_links_subuser_delete', () => { + const request = {}; + request.qs = { + username: 'test_string', + }; + request.method = 'DELETE'; + request.url = '/v3/whitelabel/links/subuser'; + xit('should have the correct response code', () => { + return testRequest(request, 204); + }); +}); + +describe('test_whitelabel_links_subuser_get', () => { + const request = {}; + request.qs = { + username: 'test_string', + }; + request.method = 'GET'; + request.url = '/v3/whitelabel/links/subuser'; + it('should have the correct response code', () => { + return testRequest(request, 200); + }); +}); + +describe('test_whitelabel_links__id__delete', () => { + const request = {}; + request.method = 'DELETE'; + request.url = '/v3/whitelabel/links/{id}'; + xit('should have the correct response code', () => { + return testRequest(request, 204); + }); +}); + +describe('test_whitelabel_links__id__patch', () => { + const request = {}; + request.body = { + default: true, + }; + request.method = 'PATCH'; + request.url = '/v3/whitelabel/links/{id}'; + it('should have the correct response code', () => { + return testRequest(request, 200); + }); +}); + +describe('test_whitelabel_links__id__get', () => { + const request = {}; + request.method = 'GET'; + request.url = '/v3/whitelabel/links/{id}'; + it('should have the correct response code', () => { + return testRequest(request, 200); + }); +}); + +describe('test_whitelabel_links__id__validate_post', () => { + const request = {}; + request.method = 'POST'; + request.url = '/v3/whitelabel/links/{id}/validate'; + it('should have the correct response code', () => { + return testRequest(request, 200); + }); +}); + +describe('test_whitelabel_links__link_id__subuser_post', () => { + const request = {}; + request.body = { + username: 'jane@example.com', + }; + request.method = 'POST'; + request.url = '/v3/whitelabel/links/{link_id}/subuser'; + it('should have the correct response code', () => { + return testRequest(request, 200); + }); +}); + +describe('setDataResidency', () => { + let consoleWarnSpy; + beforeEach(() => { + testClient = require('./client'); + consoleWarnSpy = sinon.spy(console, 'warn'); + }); + afterEach(() => { + console.warn.restore(); + }); + it('should have default value of hostname as https://api.sendgrid.com/', () => { + expect(testClient.defaultRequest.baseUrl).to.equal('https://api.sendgrid.com/'); + expect(testClient.sendgrid_region).to.equal('global'); + }); + it('should send to host EU', () => { + testClient.setDataResidency('eu'); + expect(testClient.defaultRequest.baseUrl).to.equal('https://api.eu.sendgrid.com/'); + }); + it('should send to host Global/default', () => { + testClient.setDataResidency('global'); + expect(testClient.defaultRequest.baseUrl).to.equal('https://api.sendgrid.com/'); + expect(testClient.sendgrid_region).to.equal('global'); + }); + it('should override the existing set hostname, if data residency setter is called after', () => { + testClient.setApiKey('SG.1234567890'); + testClient.setDataResidency('eu'); + expect(testClient.defaultRequest.baseUrl).to.equal('https://api.eu.sendgrid.com/'); + }); + it('should give a warning if the provided value is not allowed', () => { + testClient.setDataResidency(''); + expect(consoleWarnSpy.calledOnce).to.equal(true); + }); + it('should give a warning if the provided value is null', () => { + testClient.setDataResidency(null); + expect(consoleWarnSpy.calledOnce).to.equal(true); + }); + it('setting the API Key wont reset the region set', () => { + testClient.setDataResidency('eu'); + testClient.setApiKey('SG.1234567890'); + expect(testClient.defaultRequest.baseUrl).to.equal('https://api.eu.sendgrid.com/'); + expect(testClient.sendgrid_region).to.equal('eu'); + }); + it('should send to host global and then call setApiKey', () => { + testClient.setDataResidency('global'); + testClient.setApiKey('SG.1234567890'); + expect(testClient.defaultRequest.baseUrl).to.equal('https://api.sendgrid.com/'); + expect(testClient.sendgrid_region).to.equal('global'); + + + }); +}); + diff --git a/backend/node_modules/@sendgrid/client/src/request.d.ts b/backend/node_modules/@sendgrid/client/src/request.d.ts new file mode 100644 index 0000000..900454c --- /dev/null +++ b/backend/node_modules/@sendgrid/client/src/request.d.ts @@ -0,0 +1,3 @@ +import RequestOptions from "@sendgrid/helpers/classes/request"; + +export type ClientRequest = RequestOptions; diff --git a/backend/node_modules/@sendgrid/client/src/response.d.ts b/backend/node_modules/@sendgrid/client/src/response.d.ts new file mode 100644 index 0000000..3c84e37 --- /dev/null +++ b/backend/node_modules/@sendgrid/client/src/response.d.ts @@ -0,0 +1,3 @@ +import Response from "@sendgrid/helpers/classes/response"; + +export type ClientResponse = Response; diff --git a/backend/node_modules/@sendgrid/helpers/LICENSE b/backend/node_modules/@sendgrid/helpers/LICENSE new file mode 100644 index 0000000..3154774 --- /dev/null +++ b/backend/node_modules/@sendgrid/helpers/LICENSE @@ -0,0 +1,21 @@ +MIT License + +Copyright (C) 2023, Twilio SendGrid, Inc.Hello HTML world!
', + templateId: 'd-df80613cccc6441ea5cd7c95377bc1ef', + }; + }); + + afterEach(() => { + console.warn.restore(); + }); + + it('should log an error if template subject line contains improperly escaped "\'" character', () => { + data = Object.assign(data, { + dynamicTemplateData: { + subject: 'Testing Templates and \'Stuff\'', + }, + }); + + const mail = new Mail(data); + + expect(logSpy.calledOnce).to.equal(true); + expect(logSpy.calledWith(DYNAMIC_TEMPLATE_CHAR_WARNING)).to.equal(true); + }); + + it('should log an error if template subject line contains improperly escaped """ character', () => { + data = Object.assign(data, { + dynamicTemplateData: { + subject: '"Testing Templates" and Stuff', + }, + }); + + const mail = new Mail(data); + + expect(logSpy.calledOnce).to.equal(true); + expect(logSpy.calledWith(DYNAMIC_TEMPLATE_CHAR_WARNING)).to.equal(true); + }); + + it('should log an error if template subject line contains improperly escaped "&" character', () => { + data = Object.assign(data, { + dynamicTemplateData: { + subject: 'Testing Templates & Stuff', + }, + }); + + const mail = new Mail(data); + + expect(logSpy.calledOnce).to.equal(true); + expect(logSpy.calledWith(DYNAMIC_TEMPLATE_CHAR_WARNING)).to.equal(true); + }); + }); + + describe('set replyToList to set multiple reply-to', () => { + let data; + + this.beforeEach(() => { + data = { + to: 'send-to@example.org', + from: 'sender@example.org', + subject: 'test replyToList', + category: 'test', + text: 'Testing replyToList settings', + html: 'Testing replyToList settings
', + }; + }); + + it('should set the replyToList', () => { + let replyToList = [ + { + 'name': 'Test User1', + 'email': 'test_user1@example.org' + }, + { + 'email': 'test_user2@example.org' + } + ]; + data.replyToList = replyToList; + + const mail = new Mail(data); + + expect(mail.replyToList) + .to.be.deep.equal(replyToList); + }); + + it('should throw error for incorrect replyToList format', () => { + let replyToList = [ + { + 'name': 'Test User1' + }, + { + 'email_data': 'test_user2@example.org' + } + ]; + data.replyToList = replyToList; + + expect(() => new Mail(data)) + .to.throw('Expected each replyTo to contain an `email` string'); + }); + + it('should throw error for as replyToList is not an array', () => { + let replyToList = { + 'name': 'Test User1', + 'email': 'test_user1@example.org' + }; + data.replyToList = replyToList; + expect(() => new Mail(data)) + .to.throw('Array expected for`replyToList`'); + }); + }); +}); diff --git a/backend/node_modules/@sendgrid/helpers/classes/personalization.d.ts b/backend/node_modules/@sendgrid/helpers/classes/personalization.d.ts new file mode 100644 index 0000000..43163ab --- /dev/null +++ b/backend/node_modules/@sendgrid/helpers/classes/personalization.d.ts @@ -0,0 +1,128 @@ +import { EmailData, EmailJSON } from "./email-address"; + +export interface PersonalizationData { + to: EmailData | EmailData[], + from?: EmailData, + cc?: EmailData | EmailData[], + bcc?: EmailData | EmailData[], + subject?: string; + headers?: { [key: string]: string }; + substitutions?: { [key: string]: string }; + dynamicTemplateData?: { [key: string]: any; }; + customArgs?: { [key: string]: string }; + sendAt?: number; +} + +export interface PersonalizationJSON { + to: EmailJSON | EmailJSON[]; + from?: EmailJSON; + cc?: EmailJSON[]; + bcc?: EmailJSON[]; + headers?: { [key: string]: string; }; + substitutions?: { [key: string]: string; }; + dynamic_template_data?: { [key: string]: string; }; + custom_args?: { [key: string]: string; }; + subject?: string; + send_at?: number; +} + +export default class Personalization { + constructor(data?: PersonalizationData); + + fromData(data: PersonalizationData): void; + + /** + * Set subject + */ + setSubject(subject: string): void; + + /** + * Set send at + */ + setSendAt(sendAt: number): void; + + /** + * Set to + */ + setTo(to: EmailData | EmailData[]): void; + + /** + * Set from + */ + setFrom(from: EmailData): void; + + /** + * Add a single to + */ + addTo(to: EmailData): void; + + /** + * Set cc + */ + setCc(cc: EmailData | EmailData[]): void; + + /** + * Add a single cc + */ + addCc(cc: EmailData): void; + + /** + * Set bcc + */ + setBcc(bcc: EmailData | EmailData[]): void; + + /** + * Add a single bcc + */ + addBcc(bcc: EmailData): void; + + /** + * Set headers + */ + setHeaders(headers: { [key: string]: string }): void; + + /** + * Add a header + */ + addHeader(key: string, value: string): void; + + /** + * Set custom args + */ + setCustomArgs(customArgs: { [key: string]: string }): void; + + /** + * Add a custom arg + */ + addCustomArg(key: string, value: string): void; + + /** + * Set substitutions + */ + setSubstitutions(substitutions: { [key: string]: string }): void; + + /** + * Add a substitution + */ + addSubstitution(key: string, value: string): void; + + /** + * Reverse merge substitutions, preserving existing ones + */ + reverseMergeSubstitutions(substitutions: { [key: string]: string }): void; + + /** + * Set substitution wrappers + */ + setSubstitutionWrappers(wrappers: string[]): void; + + /** + * Set dynamic template data + */ + setDynamicTemplateData(dynamicTemplateData: { [key: string]: any }): void; + + /** + * To JSON + */ + toJSON(): PersonalizationJSON; +} \ No newline at end of file diff --git a/backend/node_modules/@sendgrid/helpers/classes/personalization.js b/backend/node_modules/@sendgrid/helpers/classes/personalization.js new file mode 100644 index 0000000..188113b --- /dev/null +++ b/backend/node_modules/@sendgrid/helpers/classes/personalization.js @@ -0,0 +1,371 @@ +'use strict'; + +/** + * Dependencies + */ +const EmailAddress = require('./email-address'); +const toCamelCase = require('../helpers/to-camel-case'); +const toSnakeCase = require('../helpers/to-snake-case'); +const deepClone = require('../helpers/deep-clone'); +const deepMerge = require('deepmerge'); +const wrapSubstitutions = require('../helpers/wrap-substitutions'); + +/** + * Personalization class + */ +class Personalization { + + /** + * Constructor + */ + constructor(data) { + + //Init array and object placeholders + this.to = []; + this.cc = []; + this.bcc = []; + this.headers = {}; + this.customArgs = {}; + this.substitutions = {}; + this.substitutionWrappers = ['{{', '}}']; + this.dynamicTemplateData = {}; + + //Build from data if given + if (data) { + this.fromData(data); + } + } + + /** + * From data + */ + fromData(data) { + + //Expecting object + if (typeof data !== 'object') { + throw new Error('Expecting object for Mail data'); + } + + //Convert to camel case to make it workable, making a copy to prevent + //changes to the original objects + data = deepClone(data); + data = toCamelCase(data, ['substitutions', 'dynamicTemplateData', 'customArgs', 'headers']); + + //Extract properties from data + const { + to, from, cc, bcc, subject, headers, customArgs, sendAt, + substitutions, substitutionWrappers, dynamicTemplateData, + } = data; + + //Set data + this.setTo(to); + this.setFrom(from); + this.setCc(cc); + this.setBcc(bcc); + this.setSubject(subject); + this.setHeaders(headers); + this.setSubstitutions(substitutions); + this.setSubstitutionWrappers(substitutionWrappers); + this.setCustomArgs(customArgs); + this.setDynamicTemplateData(dynamicTemplateData); + this.setSendAt(sendAt); + } + + /** + * Set subject + */ + setSubject(subject) { + if (typeof subject === 'undefined') { + return; + } + if (typeof subject !== 'string') { + throw new Error('String expected for `subject`'); + } + this.subject = subject; + } + + /** + * Set send at + */ + setSendAt(sendAt) { + if (typeof sendAt === 'undefined') { + return; + } + if (!Number.isInteger(sendAt)) { + throw new Error('Integer expected for `sendAt`'); + } + this.sendAt = sendAt; + } + + /** + * Set to + */ + setTo(to) { + if (typeof to === 'undefined') { + return; + } + if (!Array.isArray(to)) { + to = [to]; + } + this.to = EmailAddress.create(to); + } + + /** + * Set from + * */ + setFrom(from) { + if (typeof from === 'undefined') { + return; + } + this.from = EmailAddress.create(from); + } + + /** + * Add a single to + */ + addTo(to) { + if (typeof to === 'undefined') { + return; + } + this.to.push(EmailAddress.create(to)); + } + + /** + * Set cc + */ + setCc(cc) { + if (typeof cc === 'undefined') { + return; + } + if (!Array.isArray(cc)) { + cc = [cc]; + } + this.cc = EmailAddress.create(cc); + } + + /** + * Add a single cc + */ + addCc(cc) { + if (typeof cc === 'undefined') { + return; + } + this.cc.push(EmailAddress.create(cc)); + } + + /** + * Set bcc + */ + setBcc(bcc) { + if (typeof bcc === 'undefined') { + return; + } + if (!Array.isArray(bcc)) { + bcc = [bcc]; + } + this.bcc = EmailAddress.create(bcc); + } + + /** + * Add a single bcc + */ + addBcc(bcc) { + if (typeof bcc === 'undefined') { + return; + } + this.bcc.push(EmailAddress.create(bcc)); + } + + /** + * Set headers + */ + setHeaders(headers) { + if (typeof headers === 'undefined') { + return; + } + if (typeof headers !== 'object' || headers === null) { + throw new Error('Object expected for `headers`'); + } + this.headers = headers; + } + + /** + * Add a header + */ + addHeader(key, value) { + if (typeof key !== 'string') { + throw new Error('String expected for header key'); + } + if (typeof value !== 'string') { + throw new Error('String expected for header value'); + } + this.headers[key] = value; + } + + /** + * Set custom args + */ + setCustomArgs(customArgs) { + if (typeof customArgs === 'undefined') { + return; + } + if (typeof customArgs !== 'object' || customArgs === null) { + throw new Error('Object expected for `customArgs`'); + } + this.customArgs = customArgs; + } + + /** + * Add a custom arg + */ + addCustomArg(key, value) { + if (typeof key !== 'string') { + throw new Error('String expected for custom arg key'); + } + if (typeof value !== 'string') { + throw new Error('String expected for custom arg value'); + } + this.customArgs[key] = value; + } + + /** + * Set substitutions + */ + setSubstitutions(substitutions) { + if (typeof substitutions === 'undefined') { + return; + } + if (typeof substitutions !== 'object') { + throw new Error('Object expected for `substitutions`'); + } + this.substitutions = substitutions; + } + + /** + * Add a substitution + */ + addSubstitution(key, value) { + if (typeof key !== 'string') { + throw new Error('String expected for substitution key'); + } + if (typeof value !== 'string' && typeof value !== 'number') { + throw new Error('String or Number expected for substitution value'); + } + this.substitutions[key] = value; + } + + /** + * Reverse merge substitutions, preserving existing ones + */ + reverseMergeSubstitutions(substitutions) { + if (typeof substitutions === 'undefined' || substitutions === null) { + return; + } + if (typeof substitutions !== 'object') { + throw new Error( + 'Object expected for `substitutions` in reverseMergeSubstitutions' + ); + } + this.substitutions = Object.assign({}, substitutions, this.substitutions); + } + + /** + * Set substitution wrappers + */ + setSubstitutionWrappers(wrappers) { + if (typeof wrappers === 'undefined' || wrappers === null) { + return; + } + + if (!Array.isArray(wrappers) || wrappers.length !== 2) { + throw new Error( + 'Array expected with two elements for `substitutionWrappers`' + ); + } + this.substitutionWrappers = wrappers; + } + + /** + * Reverse merge dynamic template data, preserving existing ones + */ + deepMergeDynamicTemplateData(dynamicTemplateData) { + if (typeof dynamicTemplateData === 'undefined' || dynamicTemplateData === null) { + return; + } + if (typeof dynamicTemplateData !== 'object') { + throw new Error( + 'Object expected for `dynamicTemplateData` in deepMergeDynamicTemplateData' + ); + } + this.dynamicTemplateData = deepMerge(dynamicTemplateData, this.dynamicTemplateData); + } + + /** + * Set dynamic template data + */ + setDynamicTemplateData(dynamicTemplateData) { + if (typeof dynamicTemplateData === 'undefined') { + return; + } + if (typeof dynamicTemplateData !== 'object') { + throw new Error('Object expected for `dynamicTemplateData`'); + } + this.dynamicTemplateData = dynamicTemplateData; + } + + /** + * To JSON + */ + toJSON() { + + //Get data from self + const { + to, from, cc, bcc, subject, headers, customArgs, sendAt, + substitutions, substitutionWrappers, dynamicTemplateData, + } = this; + + //Initialize with mandatory values + const json = {to}; + + //Arrays + if (Array.isArray(cc) && cc.length > 0) { + json.cc = cc; + } + if (Array.isArray(bcc) && bcc.length > 0) { + json.bcc = bcc; + } + + //Objects + if (Object.keys(headers).length > 0) { + json.headers = headers; + } + if (substitutions && Object.keys(substitutions).length > 0) { + const [left, right] = substitutionWrappers; + json.substitutions = wrapSubstitutions(substitutions, left, right); + } + if (Object.keys(customArgs).length > 0) { + json.customArgs = customArgs; + } + + if (dynamicTemplateData && Object.keys(dynamicTemplateData).length > 0) { + json.dynamicTemplateData = dynamicTemplateData; + } + + //Simple properties + if (typeof subject !== 'undefined') { + json.subject = subject; + } + if (typeof sendAt !== 'undefined') { + json.sendAt = sendAt; + } + if (typeof from !== 'undefined') { + json.from = from; + } + + //Return as snake cased object + return toSnakeCase(json, ['substitutions', 'dynamicTemplateData', 'customArgs', 'headers']); + } +} + +//Export class +module.exports = Personalization; diff --git a/backend/node_modules/@sendgrid/helpers/classes/personalization_specs/527-camel-case-headers.spec.js b/backend/node_modules/@sendgrid/helpers/classes/personalization_specs/527-camel-case-headers.spec.js new file mode 100644 index 0000000..e9fa1d7 --- /dev/null +++ b/backend/node_modules/@sendgrid/helpers/classes/personalization_specs/527-camel-case-headers.spec.js @@ -0,0 +1,36 @@ +'use strict'; + +/** + * Dependencies + */ +const Personalization = require('../personalization'); +const EmailAddress = require('../email-address'); + +/** + * Tests + */ +describe('Personalization', function() { + + //Create new personalization before each test + let p; + beforeEach(function() { + p = new Personalization(); + }); + + // camel case headers test + describe('#527', function() { + it('shouldn\'t convert the headers to camel/snake case', function() { + const p = new Personalization({ + to: 'test@example.com', + headers: { + 'List-Unsubscribe': 'Hello world
'; + + //Test string with nested html tags + const html2 = 'Hello World!
Hello HTML world!
', + }; + + it('should throw an error when no data provided', () => { + return expect(sgMail.send()).to.eventually.be.rejectedWith(Error); + }); + + it('should send a basic email', () => { + sgClient.setDefaultHeader('X-Mock', 202); + return sgMail + .send(data) + .then(([response, body]) => { + expect(response.statusCode).to.equal(202); + }); + }); + + it('should throw an error if callback is not a function', () => { + return expect(function() { + sgMail.send(data, false, {}); + }).to.throw(Error); + }); + + it('should include custom headers to the request', () => { + sgClient.setDefaultHeader('X-Mock', 202); + const clientSpy = sinon.spy(sgClient, "request") + return sgMail + .send(Object.assign(data, { headers: { customHeader: "Custom Header Content" } })) + .then(([response, body]) => { + expect(response.statusCode).to.equal(202); + expect(clientSpy).to.have.been.calledWith(sinon.match({ + url: "/v3/mail/send", + method: "POST", + headers: { customHeader: "Custom Header Content" } + })); + }); + }); + + it('should send email with correct replyToList format', () => { + sgClient.setDefaultHeader('X-Mock', 202); + data["replyToList"] = [ + { + "name": "Test Team", + "email": "test@example.org" + }, + { + "name": "Support Test Team", + "email": "support.test@example.org" + } + ]; + return sgMail + .send(data) + .then(([response, body]) => { + expect(response.statusCode).to.equal(202); + }); + }); + + it('should throw error with wrong replyToList format', () => { + sgClient.setDefaultHeader('X-Mock', 202); + data["replyToList"] = { + "name": "Support Test Team", + "email": "support.test@example.org" + }; + return expect(function() { + sgMail.send(data, false, {}); + }).to.throw(Error); + }); + + it('should throw error if any record in replyToList is without email', () => { + data["replyToList"] = [ + { + "name": "Test Team", + "email": "test@example.org" + }, + { + "name": "Support Test Team" + } + ]; + return expect(function() { + sgMail.send(data, false, {}); + }).to.throw(Error); + }); + + it('should throw error if both replyTo and replyToList are mentioned', () => { + data["replyTo"] = { + "name": "Manual Tester", + "email": "manual.test@example.org" + }; + data["replyToList"] = [ + { + "name": "Test Team", + "email": "test@example.org" + }, + { + "name": "Support Test Team", + "email": "support.test@example.org" + } + ]; + return expect(function() { + sgMail.send(data, false, {}); + }).to.throw(Error); + }); +}); + diff --git a/backend/node_modules/append-field/.npmignore b/backend/node_modules/append-field/.npmignore deleted file mode 100644 index c2658d7..0000000 --- a/backend/node_modules/append-field/.npmignore +++ /dev/null @@ -1 +0,0 @@ -node_modules/ diff --git a/backend/node_modules/append-field/README.md b/backend/node_modules/append-field/README.md deleted file mode 100644 index 62b901b..0000000 --- a/backend/node_modules/append-field/README.md +++ /dev/null @@ -1,44 +0,0 @@ -# `append-field` - -A [W3C HTML JSON forms spec](http://www.w3.org/TR/html-json-forms/) compliant -field appender (for lack of a better name). Useful for people implementing -`application/x-www-form-urlencoded` and `multipart/form-data` parsers. - -It works best on objects created with `Object.create(null)`. Otherwise it might -conflict with variables from the prototype (e.g. `hasOwnProperty`). - -## Installation - -```sh -npm install --save append-field -``` - -## Usage - -```javascript -var appendField = require('append-field') -var obj = Object.create(null) - -appendField(obj, 'pets[0][species]', 'Dahut') -appendField(obj, 'pets[0][name]', 'Hypatia') -appendField(obj, 'pets[1][species]', 'Felis Stultus') -appendField(obj, 'pets[1][name]', 'Billie') - -console.log(obj) -``` - -```text -{ pets: - [ { species: 'Dahut', name: 'Hypatia' }, - { species: 'Felis Stultus', name: 'Billie' } ] } -``` - -## API - -### `appendField(store, key, value)` - -Adds the field named `key` with the value `value` to the object `store`. - -## License - -MIT diff --git a/backend/node_modules/append-field/index.js b/backend/node_modules/append-field/index.js deleted file mode 100644 index fc5acc8..0000000 --- a/backend/node_modules/append-field/index.js +++ /dev/null @@ -1,12 +0,0 @@ -var parsePath = require('./lib/parse-path') -var setValue = require('./lib/set-value') - -function appendField (store, key, value) { - var steps = parsePath(key) - - steps.reduce(function (context, step) { - return setValue(context, step, context[step.key], value) - }, store) -} - -module.exports = appendField diff --git a/backend/node_modules/append-field/lib/parse-path.js b/backend/node_modules/append-field/lib/parse-path.js deleted file mode 100644 index 31d6179..0000000 --- a/backend/node_modules/append-field/lib/parse-path.js +++ /dev/null @@ -1,53 +0,0 @@ -var reFirstKey = /^[^\[]*/ -var reDigitPath = /^\[(\d+)\]/ -var reNormalPath = /^\[([^\]]+)\]/ - -function parsePath (key) { - function failure () { - return [{ type: 'object', key: key, last: true }] - } - - var firstKey = reFirstKey.exec(key)[0] - if (!firstKey) return failure() - - var len = key.length - var pos = firstKey.length - var tail = { type: 'object', key: firstKey } - var steps = [tail] - - while (pos < len) { - var m - - if (key[pos] === '[' && key[pos + 1] === ']') { - pos += 2 - tail.append = true - if (pos !== len) return failure() - continue - } - - m = reDigitPath.exec(key.substring(pos)) - if (m !== null) { - pos += m[0].length - tail.nextType = 'array' - tail = { type: 'array', key: parseInt(m[1], 10) } - steps.push(tail) - continue - } - - m = reNormalPath.exec(key.substring(pos)) - if (m !== null) { - pos += m[0].length - tail.nextType = 'object' - tail = { type: 'object', key: m[1] } - steps.push(tail) - continue - } - - return failure() - } - - tail.last = true - return steps -} - -module.exports = parsePath diff --git a/backend/node_modules/append-field/lib/set-value.js b/backend/node_modules/append-field/lib/set-value.js deleted file mode 100644 index c15e873..0000000 --- a/backend/node_modules/append-field/lib/set-value.js +++ /dev/null @@ -1,64 +0,0 @@ -function valueType (value) { - if (value === undefined) return 'undefined' - if (Array.isArray(value)) return 'array' - if (typeof value === 'object') return 'object' - return 'scalar' -} - -function setLastValue (context, step, currentValue, entryValue) { - switch (valueType(currentValue)) { - case 'undefined': - if (step.append) { - context[step.key] = [entryValue] - } else { - context[step.key] = entryValue - } - break - case 'array': - context[step.key].push(entryValue) - break - case 'object': - return setLastValue(currentValue, { type: 'object', key: '', last: true }, currentValue[''], entryValue) - case 'scalar': - context[step.key] = [context[step.key], entryValue] - break - } - - return context -} - -function setValue (context, step, currentValue, entryValue) { - if (step.last) return setLastValue(context, step, currentValue, entryValue) - - var obj - switch (valueType(currentValue)) { - case 'undefined': - if (step.nextType === 'array') { - context[step.key] = [] - } else { - context[step.key] = Object.create(null) - } - return context[step.key] - case 'object': - return context[step.key] - case 'array': - if (step.nextType === 'array') { - return currentValue - } - - obj = Object.create(null) - context[step.key] = obj - currentValue.forEach(function (item, i) { - if (item !== undefined) obj['' + i] = item - }) - - return obj - case 'scalar': - obj = Object.create(null) - obj[''] = currentValue - context[step.key] = obj - return obj - } -} - -module.exports = setValue diff --git a/backend/node_modules/append-field/package.json b/backend/node_modules/append-field/package.json deleted file mode 100644 index 8d6e716..0000000 --- a/backend/node_modules/append-field/package.json +++ /dev/null @@ -1,19 +0,0 @@ -{ - "name": "append-field", - "version": "1.0.0", - "license": "MIT", - "author": "Linus Unnebäck ![]() API-first authentication, authorization, and fraud prevention + | We’re bound by one common purpose: to give you the financial tools, resources and information you ne... + | ![]() Buy real Instagram followers from Twicsy starting at only $2.97. Twicsy has been voted the best site... + |
![]() Hi, we're Descope! We are building something in the authentication space for app developers and... + | ![]() At Buzzoid, you can buy Instagram followers quickly, safely, and easily with just a few clicks. Rate... + | ![]() At Famety, you can grow your social media following quickly, safely, and easily with just a few clic... + |
![]() Buy Instagram Likes + | ![]() Ставки на спорт, БК в Україні + | ![]() SS Market offers professional social media services that rapidly increase your YouTube subscriber co... + |
💜 Become a sponsor + | 💜 Become a sponsor + | 💜 Become a sponsor + |
Promise based HTTP client for the browser and node.js
+ ++ Website • + Documentation +
+ +