#include "common/Email.h" #include #include #include #include #include #include #include namespace visione::email { namespace { std::string configString(const std::string &key, const std::string &fallback) { const auto &mail = drogon::app().getCustomConfig()["mail"]; return mail.get(key, fallback).asString(); } int configInt(const std::string &key, int fallback) { const auto &mail = drogon::app().getCustomConfig()["mail"]; return mail.get(key, fallback).asInt(); } bool readResponse(int socket) { std::array buffer{}; const auto count = recv(socket, buffer.data(), buffer.size() - 1, 0); return count > 0 && buffer[0] >= '2' && buffer[0] <= '3'; } bool sendLine(int socket, const std::string &line) { const auto payload = line + "\r\n"; return send(socket, payload.data(), payload.size(), 0) == static_cast(payload.size()); } bool sendCommand(int socket, const std::string &line) { return sendLine(socket, line) && readResponse(socket); } } // namespace bool EmailService::sendOtp(const std::string &to, const std::string &code) const { const auto host = configString("smtp_host", "127.0.0.1"); const auto port = std::to_string(configInt("smtp_port", 1025)); const auto from = configString("from", "noreply@visione.local"); addrinfo hints{}; hints.ai_family = AF_UNSPEC; hints.ai_socktype = SOCK_STREAM; addrinfo *addresses = nullptr; if (getaddrinfo(host.c_str(), port.c_str(), &hints, &addresses) != 0) { return false; } int smtp = -1; for (auto *address = addresses; address != nullptr; address = address->ai_next) { smtp = socket(address->ai_family, address->ai_socktype, address->ai_protocol); if (smtp < 0) { continue; } if (connect(smtp, address->ai_addr, address->ai_addrlen) == 0) { break; } close(smtp); smtp = -1; } freeaddrinfo(addresses); if (smtp < 0) { return false; } const auto closeSocket = [&smtp]() { if (smtp >= 0) { close(smtp); smtp = -1; } }; if (!readResponse(smtp) || !sendCommand(smtp, "HELO visione.local") || !sendCommand(smtp, "MAIL FROM:<" + from + ">") || !sendCommand(smtp, "RCPT TO:<" + to + ">") || !sendCommand(smtp, "DATA")) { closeSocket(); return false; } const std::string body = "From: Visione <" + from + ">\r\n" "To: " + to + "\r\n" "Subject: Codice OTP Visione\r\n" "Content-Type: text/plain; charset=UTF-8\r\n" "\r\n" "Il tuo codice OTP per Visione e': " + code + "\r\n" "Scade tra 10 minuti.\r\n" "."; const auto ok = sendCommand(smtp, body) && sendCommand(smtp, "QUIT"); closeSocket(); return ok; } } // namespace visione::email