【php】SMTPの認証方式CRAM-MD5を実装する
問題
phpでSMTP接続してメールを送信したい。

答え
fsockopenで587番ポートに話しかけます。
以下のような形になります。
<?php
$smtp_id = 'test@example.com';
$smtp_password = 'test-password-test-password';
$smtp_host = 'mail.example.com';
// 認証は cram-md5 で
try {
// これは1行しか返ってこない前提
$sock = fsockopen('tcp://' . $smtp_host . ':587', 587, $err, $errno, 10);
$result = fgets($sock);
if (strpos($result, '220 ') !== 0) {
throw new Exception('1001' . ' ' . $result);
}
// 複数行返ってくることがある
fwrite($sock, "EHLO " . $smtp_host . "\r\n");
do {
$result = fgets($sock);
$_ = stream_get_meta_data($sock);
} while ($_['unread_bytes'] > 0);
if (strpos($result, '250 ') !== 0) {
throw new Exception('1002' . ' ' . $result);
}
// 1行しか返ってこないはず
fwrite($sock, "AUTH CRAM-MD5" . "\r\n");
$result = fgets($sock);
if (strpos($result, '334 ') !== 0) {
throw new Exception('1003' . ' ' . $result);
}
$cc = base64_decode(substr($result, 4));
// 認証文字列送信
$authstr = base64_encode($smtp_id . ' ' . hash_hmac('md5', $cc, $smtp_password, false));
fwrite($sock, $authstr . "\r\n");
// 認証結果
$result = fgets($sock);
if (strpos($result, '235 ') !== 0) {
throw new Exception('1004' . ' ' . $result);
}
fwrite($sock, "MAIL FROM:<" . $mail['from'] . ">\r\n");
$result = fgets($sock);
fwrite($sock, "RCPT TO:<" . $mail['to'] . ">\r\n");
$result = fgets($sock);
fwrite($sock, "DATA\r\n");
$result = fgets($sock);
// $message はメールのソース
fwrite($sock, $message . "\r\n" . "." . "\r\n");
$result = fgets($sock);
if (! ereg("^250", $result)) {
throw new Exception('1005' . ' ' . $result);
}
fclose($sock);
} catch (Exception $e) {
echo $e->getMessage();
}