Move response to own class

Implement warning output
Implement warning when URL and string provided for HTML/plain
Turn allowempty to config key
Add option to prefer URL over string for HTML/plain
Add user agent to curl requests
Update OpenAPI
Bump version to 0.5
This commit is contained in:
Kumi 2020-09-05 09:12:28 +02:00
parent 48087056b5
commit 730ad8c0e1
7 changed files with 97 additions and 37 deletions

View file

@ -12,6 +12,7 @@ class File {
curl_setopt($ch, CURLOPT_URL, $this->url); curl_setopt($ch, CURLOPT_URL, $this->url);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true); curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
curl_setopt($ch, CURLOPT_FOLLOWLOCATION, $follow); curl_setopt($ch, CURLOPT_FOLLOWLOCATION, $follow);
curl_setopt($ch, CURLOPT_USERAGENT, "Mozilla/5.0 (compatible; KumiSystemsMailer/0.5; +https://expmail.kumi.systems/doc/)");
curl_setopt($ch, CURLOPT_HEADER, true); curl_setopt($ch, CURLOPT_HEADER, true);
curl_setopt($ch, CURLOPT_NOBODY, true); curl_setopt($ch, CURLOPT_NOBODY, true);
curl_setopt($ch, CURLOPT_TIMEOUT, 10); curl_setopt($ch, CURLOPT_TIMEOUT, 10);
@ -65,6 +66,7 @@ class File {
curl_setopt($ch, CURLOPT_URL, $this->url); curl_setopt($ch, CURLOPT_URL, $this->url);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true); curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
curl_setopt($ch, CURLOPT_FOLLOWLOCATION, $follow); curl_setopt($ch, CURLOPT_FOLLOWLOCATION, $follow);
curl_setopt($ch, CURLOPT_USERAGENT, "Mozilla/5.0 (compatible; KumiSystemsMailer/0.5; +https://expmail.kumi.systems/doc/)");
curl_setopt($ch, CURLOPT_HEADER, false); curl_setopt($ch, CURLOPT_HEADER, false);
curl_setopt($ch, CURLOPT_NOBODY, false); curl_setopt($ch, CURLOPT_NOBODY, false);
curl_setopt($ch, CURLOPT_TIMEOUT, 10); curl_setopt($ch, CURLOPT_TIMEOUT, 10);

View file

@ -12,14 +12,13 @@ class Mail {
global $MAIL_HOST, $MAIL_USER, $MAIL_PASS, $MAIL_STARTTLS, $MAIL_SMTPS, $MAIL_PORT; global $MAIL_HOST, $MAIL_USER, $MAIL_PASS, $MAIL_STARTTLS, $MAIL_SMTPS, $MAIL_PORT;
$this->mailer = new PHPMailer(true); $this->mailer = new PHPMailer(true);
$this->mailer->isSMTP(); $this->mailer->isSMTP();
$this->mailer->AllowEmpty = true;
$this->mailer->Host = $host ?: $MAIL_HOST; $this->mailer->Host = $host ?: $MAIL_HOST;
$this->mailer->SMTPAuth = (bool) $MAIL_USER; $this->mailer->SMTPAuth = (bool) $MAIL_USER;
$this->mailer->Username = $user ?: $MAIL_USER; $this->mailer->Username = $user ?: $MAIL_USER;
$this->mailer->Password = $password ?: $MAIL_PASS; $this->mailer->Password = $password ?: $MAIL_PASS;
$this->mailer->SMTPSecure = $MAIL_STARTTLS ? PHPMailer::ENCRYPTION_STARTTLS : ($MAIL_SMTPS ? PHPMailer::ENCRYPTION_SMTPS : false); $this->mailer->SMTPSecure = $MAIL_STARTTLS ? PHPMailer::ENCRYPTION_STARTTLS : ($MAIL_SMTPS ? PHPMailer::ENCRYPTION_SMTPS : false);
$this->mailer->Port = $port ?: ($MAIL_PORT ?: ($MAIL_SMTPS ? 465 : 587)); $this->mailer->Port = $port ?: ($MAIL_PORT ?: ($MAIL_SMTPS ? 465 : 587));
$this->mailer->XMailer = "Kumi Systems Mailer 0.1 (https://kumi.systems/)"; $this->mailer->XMailer = "Kumi Systems Mailer 0.5 (https://kumi.systems/)";
} }
function add_attachment($content, $filename=null, $cid=null) { function add_attachment($content, $filename=null, $cid=null) {
@ -68,6 +67,10 @@ class Mail {
} }
} }
function allow_empty($boolean) {
$this->mailer->AllowEmpty = $boolean;
}
static function FromRequest($req) { static function FromRequest($req) {
$mail = new self(); $mail = new self();
@ -76,12 +79,14 @@ class Mail {
$mail->add_ccs($req->get_ccs()); $mail->add_ccs($req->get_ccs());
$mail->add_bccs($req->get_bccs()); $mail->add_bccs($req->get_bccs());
$html = $req->prepare_html(); $html = $req->prepare_html($req->has_config("urlbeforestring"));
$text = $req->prepare_text(!$req->has_config("noconversion")); $text = $req->prepare_text(!$req->has_config("noconversion"), $req->has_config("urlbeforestring"));
$mail->add_content($html, $text); $mail->add_content($html, $text);
$mail->add_attachments($req->get_attachments(true, true, $req->has_config("ignoredlfails"))); $mail->add_attachments($req->get_attachments(true, true, $req->has_config("ignoredlfails")));
$mail->allow_empty($req->has_config("allowempty"));
return $mail; return $mail;
} }

View file

@ -77,8 +77,15 @@ class Request {
return $this->json["config"]; return $this->json["config"];
} }
function get_html() { function get_html($urlbeforestring=false) {
if ($this->json["html"]) { if ($this->json["html"] && $this->json["htmlurl"]) {
if ($urlbeforestring) {
trigger_error("Both `html` and `htmlurl` provided - using `htmlurl` as `urlbeforestring` config key was also provided", E_USER_WARNING);
} else {
trigger_error("Both `html` and `htmlurl` provided - using `html`", E_USER_WARNING);
}
}
if ($this->json["html"] && !$urlbeforestring) {
$html = $this->json["html"]; $html = $this->json["html"];
} else if ($this->json["htmlurl"]) { } else if ($this->json["htmlurl"]) {
try { try {
@ -87,6 +94,8 @@ class Request {
} catch (\Exception $e) { } catch (\Exception $e) {
throw new Exception("Could not fetch URL for HTML message: " . $e->getMessage()); throw new Exception("Could not fetch URL for HTML message: " . $e->getMessage());
} }
} else if ($this->json["html"]) {
$html = $this->json["html"];
} }
return $html; return $html;
@ -123,8 +132,15 @@ class Request {
} }
} }
function get_text($conversion=true) { function get_text($conversion=true, $urlbeforestring=false) {
if ($this->json["text"]) { if ($this->json["text"] && $this->json["texturl"]) {
if ($urlbeforestring) {
trigger_error("Both `text` and `texturl` provided - using `texturl` as `urlbeforestring` config key was also provided", E_USER_WARNING);
} else {
trigger_error("Both `text` and `texturl` provided - using `text`", E_USER_WARNING);
}
}
if ($this->json["text"] && !$urlbeforestring) {
$text = $this->json["text"]; $text = $this->json["text"];
} else if ($this->json["texturl"]) { } else if ($this->json["texturl"]) {
try { try {
@ -133,6 +149,8 @@ class Request {
} catch (\Exception $e) { } catch (\Exception $e) {
throw new Exception("Could not fetch URL for plain text message: " . $e->getMessage()); throw new Exception("Could not fetch URL for plain text message: " . $e->getMessage());
} }
} else if ($this->json["text"]) {
$text = $this->json["text"];
} else if ($conversion) { } else if ($conversion) {
if ($html=$this->get_html()) { if ($html=$this->get_html()) {
$text = html_entity_decode( $text = html_entity_decode(
@ -149,8 +167,8 @@ class Request {
return in_array($key, $this->get_config()); return in_array($key, $this->get_config());
} }
function prepare_html() { function prepare_html($urlbeforestring=false) {
return $this->prepare_string($this->get_html()); return $this->prepare_string($this->get_html($urlbeforestring));
} }
function prepare_string($string) { function prepare_string($string) {
@ -158,8 +176,8 @@ class Request {
return $string; return $string;
} }
function prepare_text($conversion=true) { function prepare_text($conversion=true, $urlbeforestring=false) {
return $this->prepare_string($this->get_text($conversion)); return $this->prepare_string($this->get_text($conversion, $urlbeforestring));
} }
} }

24
Response.class.php Normal file
View file

@ -0,0 +1,24 @@
<?php
class Response {
private $error;
private $warnings;
function handle_warning($warning) {
if (!$this->warnings) $this->warnings = array();
array_push($this->warnings, $warning);
}
function handle_exception($e) {
$this->error = $e->getMessage();
$this->respond();
}
function respond() {
header('Content-Type: application/json');
$response = array("status" => $this->error ? "error" : "success");
if ($this->error) $response["error"] = $this->error;
if ($this->warnings) $response["warnings"] = $this->warnings;
die(json_encode($response));
}
}

File diff suppressed because one or more lines are too long

View file

@ -1,7 +1,7 @@
openapi: 3.0.0 openapi: 3.0.0
info: info:
description: A simple endpoint to send email messages description: A simple endpoint to send email messages
version: '0.4' version: '0.5'
title: EXPMail title: EXPMail
contact: contact:
email: support@kumi.systems email: support@kumi.systems
@ -36,17 +36,18 @@ paths:
error: error:
type: string type: string
description: 'Error message, only included if an error has occurred' description: 'Error message, only included if an error has occurred'
warning:
type: array
description: 'Array of warning messages generated during the sending process, if any'
items:
type: string
servers: servers:
- url: 'https://expmail.kumi.live' - url: 'https://expmail.kumi.live'
components: components:
schemas: schemas:
Config: Config:
type: string type: string
required:
- key
properties:
key:
type: string
Placeholder: Placeholder:
type: object type: object
required: required:
@ -139,8 +140,10 @@ components:
type: array type: array
description: > description: >
Array of `Config` keys to change the default behaviour Array of `Config` keys to change the default behaviour
* `noconversion` - Do not automatically convert HTML to plain text if no plain text message is explicitly given * `allowempty` - Allow messages to have an empty body, would otherwise return an error
* `ignoredlfails` - If an attachment fails to download, just leave it out and continue processing the message * `ignoredlfails` - If an attachment fails to download, just leave it out and continue processing the message
* `noconversion` - Do not automatically convert HTML to plain text if no plain text message is explicitly given
* `urlbeforestring` - If both a string and a URL are given for the HTML or plain text content, prefer URL (else: prefer string)
items: items:
$ref: '#/components/schemas/Config' $ref: '#/components/schemas/Config'
key: key:

View file

@ -3,21 +3,27 @@
require_once 'config.php'; require_once 'config.php';
require_once 'Mail.class.php'; require_once 'Mail.class.php';
require_once 'Request.class.php'; require_once 'Request.class.php';
require_once 'Response.class.php';
function handle_exception($e) {
global $res;
$res->handle_exception($e);
}
function handle_warning($errno, $errstr) {
global $res;
if ($res) {
$res->handle_warning($errstr);
}
}
$res = new Response();
set_exception_handler("handle_exception");
set_error_handler("handle_warning", E_USER_WARNING);
try {
$req = new Request(file_get_contents('php://input')); $req = new Request(file_get_contents('php://input'));
$mail = Mail::FromRequest($req); $mail = Mail::FromRequest($req);
$mail->send(); $mail->send();
$response = array( $res->respond();
"status" => "success"
);
} catch (\Exception $e) {
$response = array(
"status" => "error",
"error" => "{$e->getMessage()}"
);
};
echo json_encode($response);