SOFTELメモ Developer's blog

会社概要 ブログ 調査依頼 採用情報 ...
技術者募集中

【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();
	}

関連するメモ

コメント