Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
14 changes: 9 additions & 5 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -64,9 +64,10 @@ They are JSON files placed in the `/targets` directory.
**Example target:**
```json
{
"smtp": "smtps://username:password@smtp.example.com",
"smtp": "smtps://sender:password@smtp.example.com",
"origin": "my-website.com",
"recipients": ["example@example.com"],
"from": "sender@example.com",
"recipients": ["recipient@example.com"],
"rateLimit": {
"timespan": 300,
"requests": 1
Expand All @@ -82,7 +83,7 @@ They are JSON files placed in the `/targets` directory.
- `smtp` *required* | A valid SMTP(S) url.
- `origin` *optional* | A HTTP origin that is used for CORS and to restrict access. Default is * if not set.
- `recipients` *required* | An array of email addresses which should receive the email.
- `from` *optional* | The "from" field of an email. This is used as fallback if no "from" is provided in the request.
- `from` *required* | The "from" field of an email.
- `key` *optional* | A string used as API key if you want to restrict access to this target.
- `redirect` *optional*:
- `success` *optional*: A valid URL to redirect the user if the mail was sent successful.
Expand All @@ -100,7 +101,8 @@ For the exact validations of the fields please see here: [target.ts](/src/models
### Fields
Whether as formular data or json, the fields are the same.

- `from` *optional* | The email address of the sender. If this filed is not set, the "from" field of your target will be used.
- `from` *optional* | The email address of the sender. This field is used as reply-to field of the email.
This field is NOT used as from field of the email to prevent email spoofing. See SPF (Sender Policy Framework) for further information.
- `firstName` *optional* | A classic first name filed which will be attached to the "from" field of the email.
- `lastName` *optional* | A classic last name filed which will be attached to the "from" field of the email.
- `subject` *required* | The email subject.
Expand Down Expand Up @@ -152,17 +154,19 @@ Content-Type: application/json
Authorization: Bearer your-optional-api-key

{
"from": "example@example.com",
"from": "user@example.com",
"subject": "your subect",
"body": "your message",
}
```

**Possible status codes:**
- `200` Email was successfully sent.
- `400` Parsing the request body failed.
- `401` Authentication failed: API key not present or wrong.
- `403` Forbidden because of wrong origin header.
- `404` Target not found.
- `422` Validation errors.
- `500` Sending the email failed.

## 👋 Contribution
Expand Down
2 changes: 1 addition & 1 deletion src/@types/target.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ export interface Target {
smtp: string;
origin: string;
recipients: string[];
from?: string;
from: string;
redirect?: Redirects;
key?: string;
rateLimit?: TargetRateLimit;
Expand Down
2 changes: 1 addition & 1 deletion src/models/target.ts
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ export const targetModel = {
},
from: {
type: "string",
presence: false
presence: true
},
redirect: {
type: "object",
Expand Down
6 changes: 3 additions & 3 deletions src/router.ts
Original file line number Diff line number Diff line change
Expand Up @@ -65,7 +65,7 @@ router.post("/:target", async (req: Request, res: Response) => {
form.parse(req, async (err, fields, files) => {
if (err) {
if(target.redirect?.error) return res.redirect(target.redirect.error);
return res.status(500).send({ message: "Parse Error" }).end();
return res.status(400).send({ message: "Parse Error" }).end();
} else {
const validationResult = validate(fields, postBody);

Expand Down Expand Up @@ -94,8 +94,8 @@ router.post("/:target", async (req: Request, res: Response) => {
const fieldBody = fields["body"] instanceof Array ? fields["body"][0] : fields["body"]

// send email
let from = EmailService.formatFromField(fieldFrom ?? target.from, fieldFirstName, fieldLastName);
let sent = await EmailService.sendMail(req.params.target, from, fieldSubject, fieldBody, files);
let replyTo = EmailService.formatFromField(fieldFrom, fieldFirstName, fieldLastName);
let sent = await EmailService.sendMail(req.params.target, target.from, replyTo, fieldSubject, fieldBody, files);

if(sent instanceof Error || !sent) {
if(target.redirect?.error) return res.redirect(target.redirect.error);
Expand Down
5 changes: 3 additions & 2 deletions src/services/email.ts
Original file line number Diff line number Diff line change
Expand Up @@ -78,12 +78,13 @@ export class EmailService {
* Send an email
* @param targetName (file-)name of an existing and loaded target
* @param from Email from field
* @param replyTo Email reply-to field
* @param subject Email subject field
* @param body Email body
* @param files Formidable files
* @return Promise<boolean|Error> True if success, error object if not success
*/
public static async sendMail(targetName: string, from: string, subject: string, body: string, files: FormidableFiles): Promise<boolean|Error> {
public static async sendMail(targetName: string, from: string, replyTo: string, subject: string, body: string, files: FormidableFiles): Promise<boolean|Error> {

if(!this.targetTransports.has(targetName)) return false;

Expand All @@ -94,7 +95,7 @@ export class EmailService {
try {
await transporter.sendMail({
from,
replyTo: from,
replyTo,
to: target.recipients,
subject,
html: body,
Expand Down