diff --git a/.gitignore b/.gitignore index fd4f2b0..0738cb5 100644 --- a/.gitignore +++ b/.gitignore @@ -1,2 +1,3 @@ node_modules .DS_Store +dist \ No newline at end of file diff --git a/.prettierrc b/.prettierrc new file mode 100644 index 0000000..3b83827 --- /dev/null +++ b/.prettierrc @@ -0,0 +1,8 @@ +{ + "arrowParens": "avoid", + "printWidth": 80, + "semi": true, + "singleQuote": true, + "trailingComma": "all", + "tabWidth": 4 +} \ No newline at end of file diff --git a/Client.js b/Client.js deleted file mode 100644 index 83dbb2d..0000000 --- a/Client.js +++ /dev/null @@ -1,43 +0,0 @@ -var Promise = require('promise'); -var https = require('https'); -var concatStream = require('concat-stream'); - -function Client(host, serverKey) { - this.host = host; - this.serverKey = serverKey; -} - -Client.prototype.makeRequest = function makeRequest(controller, action, parameters) { - return new Promise(function (resolve, reject) { - var data = JSON.stringify(parameters); - - var request = https.request({ - headers: { - 'Content-Type': 'application/json', - 'X-Server-API-Key': this.serverKey - }, - host: this.host, - method: 'POST', - path: '/api/v1/' + controller + '/' + action - }, function (response) { - response.pipe(concatStream(function (content) { - var json = JSON.parse(content); - if (json.status === 'success') { - resolve(json.data); - } else { - reject(json.data); - } - })); - }); - - request.on('error', function (error) { - reject(error); - }); - - request.write(data); - - request.end(); - }.bind(this)); -}; - -module.exports = Client; diff --git a/Message.js b/Message.js deleted file mode 100644 index bc0341e..0000000 --- a/Message.js +++ /dev/null @@ -1,14 +0,0 @@ -function Message(client, attributes) { - this.client = client; - this.attributes = attributes; -} - -Message.prototype.id = function id() { - return this.attributes.id; -} - -Message.prototype.token = function token() { - return this.attributes.token; -} - -module.exports = Message; diff --git a/README.md b/README.md index f66553a..8fcfc8c 100644 --- a/README.md +++ b/README.md @@ -1,69 +1,68 @@ # Postal for Node This library helps you send e-mails through the open source mail delivery -platform, [Postal](https://github.com/atech/postal) in Node. +platform, [Postal](https://github.com/postalserver/postal) in Node. ## Installation -Install the library using [NPM](https://www.npmjs.com/): +Install the library using [NPM](https://www.npmjs.com/) or [Yarn](https://classic.yarnpkg.com/lang/en/docs/install/): ``` -$ npm install @atech/postal --save +$ npm install @atech/postal +$ yarn install @atech/postal ``` ## Usage Sending an email is very simple. Just follow the example below. Before you can begin, you'll need to login to your installation's web interface and generate -new API credentials. +new API credentials. This package assumes you are on Postal v2. ```javascript // Include the Postal library -var Postal = require('@atech/postal'); - -// Create a new Postal client using a server key generated using your -// installation's web interface -var client = new Postal.Client('https://postal.yourdomain.com', 'your-api-key'); - -// Create a new message -var message = new Postal.SendMessage(client); - -// Add some recipients -message.to('john@example.com'); -message.to('mary@example.com'); -message.cc('mike@example.com'); -message.bcc('secret@awesomeapp.com'); - -// Specify who the message should be from - this must be from a verified domain -// on your mail server -message.from('test@test.postal.io'); - -// Set the subject -message.subject('Hi there!'); - -// Set the content for the e-mail -message.plainBody('Hello world!'); -message.htmlBody('
Hello world!
'); - -// Add any custom headers -message.header('X-PHP-Test', 'value'); - -// Attach any files -message.attach('textmessage.txt', 'text/plain', 'Hello world!'); - -// Send the message and get the result -message.send() - .then(function (result) { - var recipients = result.recipients(); - // Loop through each of the recipients to get the message ID - for (var email in recipients) { - var message = recipients[email]; - console.log(message.id()); // Logs the message ID - console.log(message.token()); // Logs the message's token - } - }).catch(function (error) { - // Do something with the error - console.log(error.code); - console.log(error.message); - }); +const Postal = require('@atech/postal').default; // CommonJS +// OR +import Postal from '@atech/postal' // ES6 import + +// Create a new Postal client using a server key generated using your installation's web interface +const client = new Postal({ + hostname: 'https://postal.yourdomain.com', + apiKey: 'your-api-key', +}); + +// This must be in an async function +try { + // Send a new message + const message = await client.sendMessage({ + // Set the subject + subject: 'Hi there!', + // Specify who the message should be from - this must be from a verified domain on your mail server + from: 'test@test.postal.io', + // Add some recipients + to: ['john@example.com', 'mary@example.com'], + cc: ['mike@example.com'], + bcc: ['secret@awesomeapp.com'], + // Set the content for the e-mail + plain_body: 'Hello world!', + html_body: 'Hello world!
', + // Add any custom headers + headers: { + 'X-PHP-Test': 'value', + }, + // Attach any files + attachments: [ + { + content_type: 'text/plain', + data: Buffer.from('Hello world!').toString('base64'), + name: 'textmessage.txt', + }, + ], + }); + + // Do something with the returned data + console.log(message); +} catch (error) { + // Handle the error + console.log(error); +} ``` diff --git a/SendMessage.js b/SendMessage.js deleted file mode 100644 index ccbe2ea..0000000 --- a/SendMessage.js +++ /dev/null @@ -1,74 +0,0 @@ -var SendResult = require('./SendResult'); - -function SendMessage(client) { - this.attributes = { - to: [], - cc: [], - bcc: [], - headers: {}, - attachments: [] - }; - this.client = client; -} - -SendMessage.prototype.to = function to(address) { - this.attributes.to.push(address); -}; - -SendMessage.prototype.cc = function cc(address) { - this.attributes.cc.push(address); -}; - -SendMessage.prototype.bcc = function bcc(address) { - this.attributes.bcc.push(address); -}; - -SendMessage.prototype.from = function from(address) { - this.attributes.from = address; -}; - -SendMessage.prototype.sender = function sender(address) { - this.attributes.sender = address; -}; - -SendMessage.prototype.subject = function subject(_subject) { - this.attributes.subject = _subject; -}; - -SendMessage.prototype.tag = function tag(_tag) { - this.attributes.tag = _tag; -}; - -SendMessage.prototype.replyTo = function replyTo(_replyTo) { - this.attributes.reply_to = _replyTo; -}; - -SendMessage.prototype.plainBody = function plainBody(content) { - this.attributes.plain_body = content; -}; - -SendMessage.prototype.htmlBody = function htmlBody(content) { - this.attributes.html_body = content; -}; - -SendMessage.prototype.header = function header(key, value) { - this.attributes.headers[key] = value; -}; - -SendMessage.prototype.attach = function attach(filename, contentType, data) { - var attachment = { - content_type: contentType, - data: new Buffer(data).toString('base64'), - name: filename - }; - this.attributes.attachments.push(attachment); -}; - -SendMessage.prototype.send = function send() { - return this.client.makeRequest('send', 'message', this.attributes) - .then(function (result) { - return new SendResult(this.client, result); - }.bind(this)); -}; - -module.exports = SendMessage; diff --git a/SendRawMessage.js b/SendRawMessage.js deleted file mode 100644 index 79c796c..0000000 --- a/SendRawMessage.js +++ /dev/null @@ -1,28 +0,0 @@ -var SendResult = require('./SendResult'); - -function SendRawMessage(client) { - this.attributes = {}; - this.client = client; -} - -SendRawMessage.prototype.mailFrom = function mailFrom(address) { - this.attributes.mail_from = address; -}; - -SendRawMessage.prototype.rcptTo = function rcptTo(address) { - this.attributes.rcpt_to = (this.attributes.rcpt_to || []); - this.attributes.rcpt_to.push(address); -}; - -SendRawMessage.prototype.data = function data(content) { - this.attributes.data = new Buffer(content).toString('base64'); -}; - -SendRawMessage.prototype.send = function send(callback) { - return this.client.makeRequest('send', 'raw', this.attributes) - .then(function (result) { - return new SendResult(this.client, result); - }.bind(this)); -}; - -module.exports = SendRawMessage; diff --git a/SendResult.js b/SendResult.js deleted file mode 100644 index 99e111a..0000000 --- a/SendResult.js +++ /dev/null @@ -1,26 +0,0 @@ -var Message = require('./Message'); - -function SendResult(client, result) { - this.client = client; - this.result = result; -} - -SendResult.prototype.recipients = function recipients() { - var messages; - - if (!this._recipients) { - this._recipients = {}; - messages = this.result.messages; - for (var key in messages) { - this._recipients[key.toLowerCase()] = new Message(this.client, messages[key]); - } - } - - return this._recipients; -}; - -SendResult.prototype.size = function size() { - return this.recipients.length; -}; - -module.exports = SendResult; diff --git a/index.js b/index.js deleted file mode 100644 index ddee6b1..0000000 --- a/index.js +++ /dev/null @@ -1,9 +0,0 @@ -var Client = require('./Client'); -var SendMessage = require('./SendMessage'); -var SendRawMessage = require('./SendRawMessage'); - -module.exports = { - Client: Client, - SendMessage: SendMessage, - SendRawMessage: SendRawMessage -}; diff --git a/index.ts b/index.ts new file mode 100644 index 0000000..4184e66 --- /dev/null +++ b/index.ts @@ -0,0 +1,104 @@ +import axios from 'axios'; +import { z } from 'zod'; +import { SendMessage, GetMessage, SendRawMessage } from './schemas'; +import type { + PostalHash, + PostalMessage, + PostalError, + PostalResponse, +} from './types'; + +class Postal { + #hostname: string; + #apiKey: string; + + constructor({ hostname, apiKey }: { hostname: string; apiKey: string }) { + this.#hostname = hostname; + this.#apiKey = apiKey; + + if (!hostname) { + throw new Error('Hostname is required'); + } + + if (!apiKey) { + throw new Error('API Key is required'); + } + } + + async #sendRequest( + controller: string, + action: string, + parameters: Record