-
Notifications
You must be signed in to change notification settings - Fork 1
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Showing
12 changed files
with
5,625 additions
and
624 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,5 +1,5 @@ | ||
<a href="https://www.cloudmailin.com"> | ||
<img src="https://assets.cloudmailin.com/assets/favicon.png" alt="CloudMailin Logo" height="60" align="left" style="margin-right: 20px;" title="CloudMailin"> | ||
<img src="https://assets.cloudmailin.com/assets/favicon.png" alt="CloudMailin Logo" height="60" align="right" title="CloudMailin"> | ||
</a> | ||
|
||
# CloudMailin Node.js Library | ||
|
@@ -37,3 +37,26 @@ app.post("/incoming_mails/", (req, res) => { | |
res.status(201).json(mail); | ||
} | ||
``` | ||
### Sending Email | ||
```typescript | ||
import { MessageClient } from "cloudmailin" | ||
|
||
const client = new MessageClient({ username: USERNAME, apiKey: API_KEY}); | ||
const response = await client.sendMessage({ | ||
to: '[email protected]', | ||
from: '[email protected]', | ||
plain: 'test message', | ||
html: '<h1>Test Message</h1>', | ||
subject: "hello world" | ||
}); | ||
``` | ||
## Development | ||
Generating the OpenAPI reference: | ||
```sh | ||
npx openapi-typescript ./path_to/api.yaml --output ./src/models/cloudmailin-api.ts | ||
``` |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,6 @@ | ||
module.exports = { | ||
transform: { '^.+\\.ts?$': 'ts-jest' }, | ||
testEnvironment: 'node', | ||
testRegex: '/tests/.*\\.(test|spec)?\\.(ts|tsx)$', | ||
moduleFileExtensions: ['ts', 'tsx', 'js', 'jsx', 'json', 'node'] | ||
}; |
Large diffs are not rendered by default.
Oops, something went wrong.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,3 +1,14 @@ | ||
import IncomingMail from "./interfaces/IncomingMail"; | ||
import MessageClient, { MessageClientOptions } from "./messageClient"; | ||
|
||
export { IncomingMail }; | ||
import { Errors } from "./models" | ||
import { IncomingMail } from "./models"; | ||
import { Message, MessageRaw } from "./models" | ||
|
||
export * as Models from "./models" | ||
|
||
export { | ||
MessageClient, MessageClientOptions, | ||
Errors, | ||
IncomingMail, | ||
Message, MessageRaw | ||
}; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,83 @@ | ||
import { Message, MessageRaw, MessageResponse } from "./models/message"; | ||
import * as errors from "./models/errors"; | ||
import axios, { AxiosError, AxiosRequestConfig } from "axios"; | ||
|
||
// Allow us to easily fetch the current version from the package without hacks | ||
// eslint-disable-next-line @typescript-eslint/no-var-requires | ||
const { version } = require("../package.json"); | ||
|
||
export interface MessageClientOptions { | ||
username: string, | ||
apiKey: string; | ||
host?: string; | ||
baseURL?: string; | ||
} | ||
|
||
type requestMethod = AxiosRequestConfig['method']; | ||
|
||
export default class MessageClient { | ||
private options: MessageClientOptions; | ||
private version: string; | ||
|
||
constructor(options: MessageClientOptions) { | ||
this.version = version; | ||
this.options = options; | ||
|
||
this.options.host = this.options.host || "api.cloudmailin.com"; | ||
this.options.baseURL = this.options.baseURL || `https://${this.options.host}/api/v0.1`; | ||
} | ||
|
||
public sendMessage(message: Message): Promise<MessageResponse> { | ||
return this.makeRequest("POST", "/messages", message); | ||
} | ||
|
||
public sendRawMessage(message: MessageRaw): Promise<MessageResponse> { | ||
return this.makeRequest("POST", "/messages", message); | ||
} | ||
|
||
// Allow body to be anything | ||
// eslint-disable-next-line @typescript-eslint/ban-types | ||
private makeRequest<T>(method: requestMethod, path: string, body?: object): Promise<T> { | ||
const client = this.makeClient(); | ||
|
||
return client.request<T>({ | ||
method: method, | ||
url: path, | ||
data: body | ||
}) | ||
.then((response) => response.data) | ||
.catch((error) => { | ||
const newError = this.handleError(error); | ||
throw newError; | ||
}); | ||
} | ||
|
||
private handleError(error: AxiosError) { | ||
const response = error.response; | ||
const status = response?.status; | ||
|
||
switch (status) { | ||
case 422: | ||
return new errors.CloudMailinError(error.message, error); | ||
|
||
default: | ||
return new errors.CloudMailinError(error.message, error); | ||
} | ||
} | ||
|
||
private makeClient() { | ||
const baseURL = `${this.options.baseURL}/${this.options.username}`; | ||
const headers = { | ||
Authorization: `Bearer ${this.options.apiKey}`, | ||
"User-Agent": `CloudMailin-js ${this.version}` | ||
}; | ||
|
||
return axios.create({ | ||
baseURL: baseURL, | ||
responseType: "json", | ||
maxContentLength: Infinity, | ||
maxBodyLength: Infinity, | ||
headers: headers | ||
}); | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,151 @@ | ||
/** | ||
* This file was auto-generated by openapi-typescript. | ||
* Do not make direct changes to the file. | ||
*/ | ||
|
||
export interface paths { | ||
"/messages": { | ||
post: operations["sendMessage"]; | ||
}; | ||
} | ||
|
||
export interface components { | ||
schemas: { | ||
MessageCommon: { | ||
id?: string; | ||
/** | ||
* The from addrress of the email message. | ||
* This is the address to be used in the SMTP transaction itself. | ||
* Although it will be replaced with an address used for bounce handling. | ||
* This must match a `from:` header in the email headers. | ||
*/ | ||
from: string; | ||
/** | ||
* The To addrress of the email message. | ||
* This is the address to be used in the SMTP transaction itself. | ||
* This must match a `To:` header in the email headers. | ||
*/ | ||
to: string[] | string; | ||
/** | ||
* Whether to send this message in test mode. | ||
* This will validate the messge but no actually send it if true. | ||
* If the server is in test mode then it will always be in test mode | ||
* regardless of this value. | ||
*/ | ||
test_mode?: boolean; | ||
/** The subject of the email. This will override any subject set in headers or raw messages. */ | ||
subject?: string; | ||
/** Tags to */ | ||
tags?: string[] | string; | ||
}; | ||
Message: components["schemas"]["MessageCommon"] & { | ||
/** | ||
* The plain text part of the email message. | ||
* Either the plain text or the html parts are required. | ||
*/ | ||
plain?: string; | ||
/** | ||
* The HTML part of the email message. | ||
* Either the plain text or the html parts are required. | ||
*/ | ||
html?: string; | ||
headers?: { [key: string]: string }; | ||
attachments?: components["schemas"]["MessageAttachment"][]; | ||
}; | ||
MessageAttachment: { | ||
file_name: string; | ||
content: string; | ||
content_type: string; | ||
content_id?: string; | ||
}; | ||
RawMessage: components["schemas"]["MessageCommon"] & { | ||
/** | ||
* A full raw email. | ||
* This should consist of both headers and a message body. | ||
* `To` and `From` headers must be present and match those in the request. | ||
* Multiple parts, text and html or other mixed content are | ||
* acceptable but the message must be valid and RFC822 compliant. | ||
* | ||
* Any attachments intended to be sent in the Raw format must also be | ||
* encoded and included here. | ||
*/ | ||
raw?: string; | ||
}; | ||
Error: { | ||
status?: number; | ||
error?: string; | ||
}; | ||
UnauthorizedError: { | ||
status?: 401; | ||
error?: string; | ||
}; | ||
ForbiddenError: { | ||
status?: 403; | ||
error?: "Forbidden"; | ||
}; | ||
NotFoundError: { | ||
status?: 404; | ||
error?: string; | ||
}; | ||
UnprocessableEntityError: { | ||
status?: 422; | ||
/** The description of the failed validation */ | ||
error?: string; | ||
}; | ||
/** Identifier, please be aware that the format may change */ | ||
accountID: string; | ||
/** Identifier, please be aware that the format may change */ | ||
id: string; | ||
}; | ||
responses: { | ||
/** The user is not Authorized */ | ||
401: { | ||
content: { | ||
"application/json": components["schemas"]["UnauthorizedError"]; | ||
}; | ||
}; | ||
/** The user is not Authorized */ | ||
403: { | ||
content: { | ||
"application/json": components["schemas"]["ForbiddenError"]; | ||
}; | ||
}; | ||
/** Resource be found or does not belong to this account */ | ||
404: { | ||
content: { | ||
"application/json": components["schemas"]["NotFoundError"]; | ||
}; | ||
}; | ||
/** Unprocessable Entity, most likely your input does not pass validation */ | ||
422: { | ||
content: { | ||
"application/json": components["schemas"]["UnprocessableEntityError"]; | ||
}; | ||
}; | ||
}; | ||
parameters: { | ||
accountID: components["schemas"]["accountID"]; | ||
}; | ||
} | ||
|
||
export interface operations { | ||
sendMessage: { | ||
responses: { | ||
/** The message has been accepted */ | ||
202: { | ||
content: { | ||
"application/json": components["schemas"]["MessageCommon"]; | ||
}; | ||
}; | ||
401: components["responses"]["401"]; | ||
422: components["responses"]["422"]; | ||
}; | ||
requestBody: { | ||
content: { | ||
"application/json": | ||
| components["schemas"]["Message"] | ||
| components["schemas"]["RawMessage"]; | ||
}; | ||
}; | ||
}; | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,22 @@ | ||
import { AxiosError } from "axios"; | ||
|
||
export class CloudMailinError extends Error { | ||
public baseError: Error; | ||
public status?: number; | ||
public details: string; | ||
|
||
constructor(message: string, baseError: AxiosError) { | ||
const trueMessage = baseError.response?.data?.error || message; | ||
super(trueMessage); | ||
|
||
this.details = trueMessage; | ||
this.status = baseError.response?.status; | ||
this.baseError = baseError; | ||
|
||
// https://github.com/Microsoft/TypeScript/wiki/Breaking-Changes#extending-built-ins-like-error-array-and-map-may-no-longer-work | ||
Object.setPrototypeOf(this, CloudMailinError.prototype); | ||
|
||
this.name = this.constructor.name; | ||
Error.captureStackTrace(this, this.constructor); | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,5 @@ | ||
import { components } from "./cloudmailin-api"; | ||
|
||
export type Message = components['schemas']['Message']; | ||
export type MessageRaw = components['schemas']['RawMessage']; | ||
export type MessageResponse = components['schemas']['MessageCommon']; |
Oops, something went wrong.