WIP:base implementation of replacement mail manager based on libcurl

This commit is contained in:
Tina_Azure 2023-05-25 19:51:13 +02:00
parent 9e5f0a68ab
commit d9eec48d7c
1 changed files with 157 additions and 0 deletions

157
src/smtpManager.cpp Normal file
View File

@ -0,0 +1,157 @@
#ifndef SMTP_MANAGER_CPP
#define SMTP_MANAGER_CPP
#include <iostream>
#include <vector>
#include <iomanip>
#include <ctime>
#include <curl/curl.h>
#include "utilities.cpp"
namespace SMTPManager {
static const std::string END_OF_LINE = "\r\n";
static const std::string END_OF_MAIL = "\0";
struct payload {
int lines_read = 0;
std::vector<std::string> payload_data;
};
/*
* Generates the Date Time Header Segment
* Date: {day}/{month}/{year} {hour}:{minute}:{second} {delta to UTC} \r\n
*/
std::string generateEmailSegmentDateTime() {
std::time_t time = std::time(nullptr);
std::tm localTime = *std::localtime(&time);
std::ostringstream oss;
oss << "Date: " << std::put_time(&localTime, "%d/%m/%Y %H:%M:%S %z") << END_OF_LINE;
return oss.str();
}
/*
* Generates the Recipient Header Segment
* To: {Recipient Name} <{email address}>\r\n
*/
std::string generateEmailSegmentRecipient(const std::string &recipientName, const std::string &recipientEmail) {
return "To: " + recipientName + " <" + recipientEmail + ">" + END_OF_LINE;
}
/*
* Generates the Sender Header Segment
* From: {Sender Name} <{email address}>\r\n
*/
std::string generateEmailSegmentSender(const Utilities::config &configuration) {
return "From: " + configuration.emailAddressDisplay + " <" + configuration.emailAddress + ">" + END_OF_LINE;
}
/*
* Generates the Subject Header Segment
* Subject: {subject}\r\n
*/
std::string generateEmailSegmentSubject(const std::string &emailSubject) {
return "Subject: " + emailSubject + END_OF_LINE;
}
/*
* Generates the Content-Type Header Segment
*/
std::string generateEmailSegmentContentType() {
return "Content-Type: text/html; charset=UTF-8" + END_OF_LINE;
}
/*
* Generates a line for the body
* {bodyLine}\r\n
*/
std::string generateEmailSegmentBody(const std::string &body) {
return body + END_OF_LINE;
}
void fillEmailPayloadData(struct payload &payload, const Utilities::config &configuration, const std::string &recipientEmail, const std::string &recipientName, const std::string &emailSubject, const std::string &body) {
payload.payload_data.emplace_back(generateEmailSegmentDateTime());
payload.payload_data.emplace_back(generateEmailSegmentRecipient(recipientName, recipientEmail));
payload.payload_data.emplace_back(generateEmailSegmentSender(configuration));
payload.payload_data.emplace_back(generateEmailSegmentSubject(emailSubject));
payload.payload_data.emplace_back(generateEmailSegmentContentType());
payload.payload_data.emplace_back(END_OF_LINE);
payload.payload_data.emplace_back(generateEmailSegmentBody(body));
payload.payload_data.emplace_back(END_OF_MAIL);
}
/*
* curl read callback function
*/
size_t payload_source(void *ptr, size_t size, size_t nmemb, void *userp)
{
auto* payload_context = (struct payload*)userp;
const char *data;
if((size == 0) || (nmemb == 0) || ((size*nmemb) < 1)) {
return 0;
}
data = payload_context->payload_data[payload_context->lines_read].c_str();
if(data) {
size_t len = strlen(data);
memcpy(ptr, data, len);
payload_context->lines_read++;
return len;
}
return 0;
}
/*
* Generates the SMTP URL
* "smtp://{address}:{port}"
*/
std::string generateMailServerURL(const Utilities::config &configuration) {
return "smtp://" + configuration.emailServerAddress + ":" + std::to_string(configuration.emailServerPort);
}
/*
* todo:for some inexplicable reason the sent email contains an empty CC: field which needs some examination
* todo:validate header https://mailheader.org/show.cgi
* Sends an HTML Email using curl
* returns CURL Error Codes https://curl.se/libcurl/c/libcurl-errors.html
* 1 = OK
*/
int sendEmailNew(const Utilities::config &configuration, const std::string &recipientEmail, const std::string &emailSubject, const std::string &htmlBody) {
struct payload payload;
fillEmailPayloadData(payload, configuration, recipientEmail, "tmpString", emailSubject, htmlBody);//todo:change
CURL* curl;
CURLcode res = CURLE_OK;
struct curl_slist* recipients;
recipients = curl_slist_append(nullptr, "root@localhost");
curl = curl_easy_init();
if (curl) {
curl_easy_setopt(curl, CURLOPT_USERNAME, configuration.emailAddress.c_str());
curl_easy_setopt(curl, CURLOPT_PASSWORD, configuration.emailPassword.c_str());
curl_easy_setopt(curl, CURLOPT_URL, generateMailServerURL(configuration).c_str());
curl_easy_setopt(curl, CURLOPT_USE_SSL, (long)CURLUSESSL_ALL);
curl_easy_setopt(curl, CURLOPT_MAIL_FROM, configuration.emailAddress.c_str());
recipients = curl_slist_append(recipients, recipientEmail.c_str());
curl_easy_setopt(curl, CURLOPT_MAIL_RCPT, recipients);
curl_easy_setopt(curl, CURLOPT_READFUNCTION, payload_source);
curl_easy_setopt(curl, CURLOPT_READDATA, &payload);
curl_easy_setopt(curl, CURLOPT_UPLOAD, 1L);
curl_easy_setopt(curl, CURLOPT_VERBOSE, 1L);
res = curl_easy_perform(curl);
if (res != CURLE_OK)
fprintf(stderr, "curl_easy_perform() failed: %s\n",
curl_easy_strerror(res));
curl_slist_free_all(recipients);
curl_easy_cleanup(curl);
}
return (int)res;
}
}
#endif