[FIX] EmailService: aggiungi sendViaTemplate() (era mancante - Edit fallito in de09af6)

Il metodo sendViaTemplate() non era stato salvato (Edit silenziosamente fallito):
requestOtp() del portale chiamava un metodo inesistente -> errore inghiottito dal
try/catch -> OTP MAI inviato. Ora presente: POST /api/emails/send con template +
data (campo canonico relay AgileHub) + alias vars, senza logEmail (OTP fuori da email_log).

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
DevEnv nis2-agile 2026-05-31 18:35:21 +02:00
parent ccea3ab7b7
commit 006f86387b

View File

@ -118,6 +118,72 @@ class EmailService
return true;
}
/**
* Invia via TEMPLATE del relay AgileHub (POST /api/emails/send), NON send-raw.
* A differenza di send()/sendViaRelay() NON chiama logEmail(): pensato per
* messaggi che non devono lasciare traccia del contenuto a DB (es. OTP del
* portale fornitore). Il corpo e' renderizzato lato relay da template+data.
*
* @param string $to destinatario
* @param string $template slug template registrato sul relay (es. "supplier_otp")
* @param array $vars variabili di sostituzione del template
* @param string|null $brandName nome committente per branding (opzionale)
* @return bool true se il relay ha accettato (HTTP 2xx + success)
*/
public function sendViaTemplate(string $to, string $template, array $vars, ?string $brandName = null): bool
{
$base = rtrim(self::env('EMAIL_MS_URL', 'https://agilehub.agile.software/api/emails'), '/');
$key = self::env('INTERNAL_EMAIL_KEY', '');
if ($key === '') {
error_log('[EmailService] INTERNAL_EMAIL_KEY non configurata: template "' . $template . '" saltato per ' . self::maskEmail($to));
return false;
}
$payload = json_encode([
'to' => $to,
'template' => $template,
'data' => $vars, // campo canonico standard email-relay AgileHub (Handlebars)
'vars' => $vars, // alias difensivo (alcune versioni del relay leggono "vars")
'product' => 'nis2',
'brand_name' => $brandName,
'priority' => 'transactional',
], JSON_UNESCAPED_UNICODE);
$ch = curl_init($base . '/send'); // endpoint TEMPLATE (NON /send-raw)
curl_setopt_array($ch, [
CURLOPT_POST => true,
CURLOPT_POSTFIELDS => $payload,
CURLOPT_RETURNTRANSFER => true,
CURLOPT_TIMEOUT => 10,
CURLOPT_CONNECTTIMEOUT => 5,
CURLOPT_HTTPHEADER => [
'Content-Type: application/json',
'X-Internal-Key: ' . $key,
],
]);
$body = curl_exec($ch);
$errno = curl_errno($ch);
$httpCode = (int) curl_getinfo($ch, CURLINFO_HTTP_CODE);
curl_close($ch);
if ($errno !== 0) {
error_log('[EmailService] relay template unreachable (' . curl_strerror($errno) . ') per ' . self::maskEmail($to));
return false;
}
if ($httpCode < 200 || $httpCode >= 300) {
error_log('[EmailService] relay template HTTP ' . $httpCode . ' per ' . self::maskEmail($to) . ': ' . substr((string) $body, 0, 200));
return false;
}
$decoded = json_decode((string) $body, true);
if (is_array($decoded) && array_key_exists('success', $decoded) && !$decoded['success']) {
error_log('[EmailService] relay template success=false per ' . self::maskEmail($to) . ': ' . substr((string) $body, 0, 200));
return false;
}
// NESSUN logEmail(): il contenuto (OTP) non deve finire in email_log.
return true;
}
/** Maschera l'email per i log (GDPR): m***@dominio.it. */
private static function maskEmail(string $email): string
{