Skip to content

Instantly share code, notes, and snippets.

@webzunft
Created September 1, 2025 10:11
Show Gist options
  • Select an option

  • Save webzunft/9db50d1495e7d586dfa3a63d01163165 to your computer and use it in GitHub Desktop.

Select an option

Save webzunft/9db50d1495e7d586dfa3a63d01163165 to your computer and use it in GitHub Desktop.
SMTP Post Check
<?php
/** Microsoft 365 SMTP Connectivity & STARTTLS Diagnostic for port 587
* Upload, then open in the browser: https://your-domain.tld/m365_smtp_diag.php
*/
header('Content-Type: text/plain; charset=utf-8');
$host = $_GET['host'] ?? 'smtp.office365.com';
$port = (int)($_GET['port'] ?? 587);
$timeout = 15;
echo "PHP: ".PHP_VERSION.PHP_EOL;
echo "OpenSSL loaded: ".(extension_loaded('openssl') ? 'yes' : 'no').PHP_EOL;
if (defined('OPENSSL_VERSION_TEXT')) echo OPENSSL_VERSION_TEXT.PHP_EOL;
echo str_repeat('-', 60).PHP_EOL;
// 1) DNS
echo "DNS resolve for $host ...".PHP_EOL;
$recordsA = dns_get_record($host, DNS_A);
$recordsAAAA = dns_get_record($host, DNS_AAAA);
$ips = [];
foreach ($recordsA as $r) { $ips[] = $r['ip']; }
foreach ($recordsAAAA as $r) { $ips[] = $r['ipv6']; }
if (!$ips) { echo "❌ DNS-Auflösung fehlgeschlagen.\n"; exit(1); }
echo "✅ DNS OK: ".implode(', ', $ips).PHP_EOL;
// Helper: read SMTP multiline
function read_smtp($fp, $label, $max = 20) {
stream_set_timeout($fp, 10);
$lines = [];
for ($i=0;$i<$max;$i++) {
$line = fgets($fp, 2048);
if ($line === false) break;
$lines[] = rtrim($line, "\r\n");
if (preg_match('/^\d{3} /', $line)) break; // last line of multiline reply
}
echo "$label\n ".implode("\n ", $lines)."\n";
return implode("\n", $lines);
}
// 2) TCP connect
$context = stream_context_create([
'ssl' => [
'SNI_enabled' => true,
'peer_name' => $host,
'verify_peer' => true,
'verify_peer_name' => true,
'capture_peer_cert' => true,
],
'socket' => ['tcp_nodelay' => true]
]);
echo str_repeat('-', 60).PHP_EOL;
echo "TCP connect to $host:$port ...".PHP_EOL;
$fp = @stream_socket_client("tcp://$host:$port", $errno, $errstr, $timeout, STREAM_CLIENT_CONNECT, $context);
if (!$fp) { echo "❌ Verbindung fehlgeschlagen: [$errno] $errstr\n"; exit(2); }
echo "✅ TCP verbunden.\n";
// 3) SMTP Banner
$banner = read_smtp($fp, "Server banner:");
if (strpos($banner, '220') !== 0) { echo "⚠️ Unerwarteter Banner.\n"; }
// 4) EHLO
fwrite($fp, "EHLO test.example\r\n");
$ehlo = read_smtp($fp, "EHLO response:");
$hasStartTLS = stripos($ehlo, 'STARTTLS') !== false;
echo $hasStartTLS ? "✅ Server bewirbt STARTTLS.\n" : "❌ STARTTLS fehlt!\n";
// 5) STARTTLS + TLS Handshake (TLS 1.2/1.3)
fwrite($fp, "STARTTLS\r\n");
$resp = read_smtp($fp, "STARTTLS response:");
if (strpos($resp, '220') !== 0) { echo "❌ STARTTLS abgelehnt.\n"; exit(3); }
$methods = 0;
if (defined('STREAM_CRYPTO_METHOD_TLSv1_3_CLIENT')) $methods |= STREAM_CRYPTO_METHOD_TLSv1_3_CLIENT;
if (defined('STREAM_CRYPTO_METHOD_TLSv1_2_CLIENT')) $methods |= STREAM_CRYPTO_METHOD_TLSv1_2_CLIENT;
$ok = @stream_socket_enable_crypto($fp, true, $methods ?: STREAM_CRYPTO_METHOD_TLS_CLIENT);
if (!$ok) { echo "❌ TLS-Handshake fehlgeschlagen (mind. TLS 1.2 erforderlich).\n"; exit(4); }
$meta = stream_get_meta_data($fp);
$proto = isset($meta['crypto']['protocol']) ? $meta['crypto']['protocol'] : 'TLS (Protokoll nicht ermittelbar)';
echo "✅ TLS aktiv: $proto\n";
// 6) Test "QUIT"
fwrite($fp, "QUIT\r\n");
read_smtp($fp, "QUIT response:");
fclose($fp);
echo str_repeat('-', 60).PHP_EOL;
echo "RESULT: Alle Netzwerk-/TLS-Checks erfolgreich. Dieser Server sollte smtp.office365.com:587 via STARTTLS erreichen können.\n";
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment