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_RETURNTRANSFER, true);
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_NOBODY, true);
curl_setopt($ch, CURLOPT_TIMEOUT, 10);
@ -65,6 +66,7 @@ class File {
curl_setopt($ch, CURLOPT_URL, $this->url);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
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_NOBODY, false);
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;
$this->mailer = new PHPMailer(true);
$this->mailer->isSMTP();
$this->mailer->AllowEmpty = true;
$this->mailer->Host = $host ?: $MAIL_HOST;
$this->mailer->SMTPAuth = (bool) $MAIL_USER;
$this->mailer->Username = $user ?: $MAIL_USER;
$this->mailer->Password = $password ?: $MAIL_PASS;
$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->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) {
@ -68,6 +67,10 @@ class Mail {
}
}
function allow_empty($boolean) {
$this->mailer->AllowEmpty = $boolean;
}
static function FromRequest($req) {
$mail = new self();
@ -76,12 +79,14 @@ class Mail {
$mail->add_ccs($req->get_ccs());
$mail->add_bccs($req->get_bccs());
$html = $req->prepare_html();
$text = $req->prepare_text(!$req->has_config("noconversion"));
$html = $req->prepare_html($req->has_config("urlbeforestring"));
$text = $req->prepare_text(!$req->has_config("noconversion"), $req->has_config("urlbeforestring"));
$mail->add_content($html, $text);
$mail->add_attachments($req->get_attachments(true, true, $req->has_config("ignoredlfails")));
$mail->allow_empty($req->has_config("allowempty"));
return $mail;
}

View file

@ -77,8 +77,15 @@ class Request {
return $this->json["config"];
}
function get_html() {
if ($this->json["html"]) {
function get_html($urlbeforestring=false) {
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"];
} else if ($this->json["htmlurl"]) {
try {
@ -87,6 +94,8 @@ class Request {
} catch (\Exception $e) {
throw new Exception("Could not fetch URL for HTML message: " . $e->getMessage());
}
} else if ($this->json["html"]) {
$html = $this->json["html"];
}
return $html;
@ -123,8 +132,15 @@ class Request {
}
}
function get_text($conversion=true) {
if ($this->json["text"]) {
function get_text($conversion=true, $urlbeforestring=false) {
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"];
} else if ($this->json["texturl"]) {
try {
@ -133,6 +149,8 @@ class Request {
} catch (\Exception $e) {
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) {
if ($html=$this->get_html()) {
$text = html_entity_decode(
@ -149,8 +167,8 @@ class Request {
return in_array($key, $this->get_config());
}
function prepare_html() {
return $this->prepare_string($this->get_html());
function prepare_html($urlbeforestring=false) {
return $this->prepare_string($this->get_html($urlbeforestring));
}
function prepare_string($string) {
@ -158,8 +176,8 @@ class Request {
return $string;
}
function prepare_text($conversion=true) {
return $this->prepare_string($this->get_text($conversion));
function prepare_text($conversion=true, $urlbeforestring=false) {
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
info:
description: A simple endpoint to send email messages
version: '0.4'
version: '0.5'
title: EXPMail
contact:
email: support@kumi.systems
@ -36,17 +36,18 @@ paths:
error:
type: string
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:
- url: 'https://expmail.kumi.live'
components:
schemas:
Config:
type: string
required:
- key
properties:
key:
type: string
Placeholder:
type: object
required:
@ -139,8 +140,10 @@ components:
type: array
description: >
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
* `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:
$ref: '#/components/schemas/Config'
key:

View file

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