https://cssoftwaresolutions.in/mail-relay/relay.php * 3. In both Hugging Face Spaces (Settings -> Variables and secrets): secret MAIL_RELAY_TOKEN = the same token, * variable MAIL_RELAY_URL = the address of this file. * * The app posts JSON with "Authorization: Bearer ": * {"from","from_name","to","subject","html","attachments":[{"name","content"(base64)}]} * and gets {"ok":true} or {"ok":false,"error":"..."}. */ const RELAY_TOKEN = 'PASTE-A-LONG-RANDOM-TOKEN-HERE'; // same value as the Space secret MAIL_RELAY_TOKEN const RELAY_FROM = 'info@cssoftwaresolutions.tech'; // the only sender allowed (a mailbox on this hosting) const PER_HOUR = 300; // emails per hour at most const MAX_MB = 12; // largest email accepted header('Content-Type: application/json'); function answer($code, $body) { http_response_code($code); echo json_encode($body); exit; } if ($_SERVER['REQUEST_METHOD'] !== 'POST') answer(405, ['ok' => false, 'error' => 'POST only']); $auth = $_SERVER['HTTP_AUTHORIZATION'] ?? ($_SERVER['REDIRECT_HTTP_AUTHORIZATION'] ?? ''); if (function_exists('getallheaders') && $auth === '') { foreach (getallheaders() as $k => $v) { if (strtolower($k) === 'authorization') $auth = $v; } } if (RELAY_TOKEN === 'PASTE-A-LONG-RANDOM-TOKEN-HERE' || !hash_equals('Bearer ' . RELAY_TOKEN, $auth)) { answer(401, ['ok' => false, 'error' => 'bad token']); } $raw = file_get_contents('php://input', false, null, 0, (int)(MAX_MB * 1024 * 1024 * 1.4)); $p = json_decode($raw, true); if (!is_array($p)) answer(400, ['ok' => false, 'error' => 'bad request']); // hourly limit (a small counter file next to this script) $stamp = __DIR__ . '/.relay-count'; $now = time(); $times = array_filter(array_map('intval', @file($stamp, FILE_IGNORE_NEW_LINES) ?: []), fn($t) => $t > $now - 3600); if (count($times) >= PER_HOUR) answer(429, ['ok' => false, 'error' => 'hourly limit reached']); $times[] = $now; @file_put_contents($stamp, implode("\n", $times), LOCK_EX); $from = trim($p['from'] ?? ''); $to = trim($p['to'] ?? ''); if (strcasecmp($from, RELAY_FROM) !== 0) answer(200, ['ok' => false, 'error' => 'sender not allowed']); if (!filter_var($to, FILTER_VALIDATE_EMAIL)) answer(200, ['ok' => false, 'error' => 'invalid recipient']); $clean = fn($s, $n) => mb_substr(str_replace(["\r", "\n"], ' ', (string)$s), 0, $n); $subject = '=?UTF-8?B?' . base64_encode($clean($p['subject'] ?? '', 200)) . '?='; $name = $clean(str_replace('"', '', $p['from_name'] ?? ''), 80); $boundary = 'csrelay_' . bin2hex(random_bytes(8)); $alt = 'csalt_' . bin2hex(random_bytes(8)); $headers = 'From: ' . ($name !== '' ? '=?UTF-8?B?' . base64_encode($name) . '?= ' : '') . "<$from>\r\n" . "Reply-To: $from\r\nMIME-Version: 1.0\r\n" . "Content-Type: multipart/mixed; boundary=\"$boundary\""; $body = "--$boundary\r\nContent-Type: multipart/alternative; boundary=\"$alt\"\r\n\r\n" . "--$alt\r\nContent-Type: text/plain; charset=UTF-8\r\n\r\nPlease view this email in an HTML-capable mail app.\r\n" . "--$alt\r\nContent-Type: text/html; charset=UTF-8\r\nContent-Transfer-Encoding: base64\r\n\r\n" . chunk_split(base64_encode((string)($p['html'] ?? ''))) . "--$alt--\r\n"; foreach (($p['attachments'] ?? []) as $a) { $fname = $clean(basename((string)($a['name'] ?? 'file')), 120); $body .= "--$boundary\r\nContent-Type: application/octet-stream; name=\"$fname\"\r\n" . "Content-Transfer-Encoding: base64\r\nContent-Disposition: attachment; filename=\"$fname\"\r\n\r\n" . chunk_split(preg_replace('/[^A-Za-z0-9+\/=]/', '', (string)($a['content'] ?? ''))) . "\r\n"; } $body .= "--$boundary--"; if (!mail($to, $subject, $body, $headers, '-f' . $from)) { answer(200, ['ok' => false, 'error' => 'the hosting mail system refused the email']); } answer(200, ['ok' => true]);