Create a gist now

Instantly share code, notes, and snippets.

What would you like to do?
Tiny, SMTP client in PHP
<?php
/*
This is a very tiny proof-of-concept SMTP client. Currently it's over 320 characters (if the var names are compressed). Think you can build one smaller?
*/
ini_set('default_socket_timeout', 3);
$user = 'you@gmail.com';
$pass = '';
$host = 'ssl://smtp.gmail.com';
//$host = 'ssl://email-smtp.us-east-1.amazonaws.com'; //Amazon SES
$port = 465;
$to = 'him@gmail.com';
$from = 'you@gmail.com';
$template = "Subject: =?UTF-8?B?VGVzdCBFbWFpbA==?=\r\n"
."To: <him@gmail.com>\r\n"
."From: you@gmail.com\r\n"
."MIME-Version: 1.0\r\n"
."Content-Type: text/html; charset=utf-8\r\n"
."Content-Transfer-Encoding: base64\r\n\r\n"
."PGgxPlRlc3QgRW1haWw8L2gxPjxwPkhlbGxvIFRoZXJlITwvcD4=\r\n.";
if(smtp_mail($to, $from, $template, $user, $pass, $host, $port))
{
echo "Mail sent\n\n";
}
else
{
echo "Some error occured\n\n";
}
<?php
/**
* Connecto to an SMTP and send the given message
*/
function smtp_mail($to, $from, $message, $user, $pass, $host, $port)
{
if ($h = fsockopen($host, $port))
{
$data = array(
0,
"EHLO $host",
'AUTH LOGIN',
base64_encode($user),
base64_encode($pass),
"MAIL FROM: <$from>",
"RCPT TO: <$to>",
'DATA',
$message
);
foreach($data as $c)
{
$c && fwrite($h, "$c\r\n");
while(substr(fgets($h, 256), 3, 1) != ' '){}
}
fwrite($h, "QUIT\r\n");
return fclose($h);
}
}

Very nice snippet and works fine.

Can I use it in my projects?

Owner

Xeoncross commented Nov 15, 2012

Yes, like all my code it's totally free under the MIT License.

divinity76 commented May 27, 2017

thanks! very easy to understand. (ahm, except the foreach loop)

ini_set('default_socket_timeout', 3); , the 3 should actually be quoted like '3' , else PHP7 will complain about incompatible types (string vs int) in php7's strict_mode - and it is actually supposed to be a string even in PHP5, its just that PHP5 silently convert it (as will php7 when strict_mode is disabled)

also.. this won't work by default on gmail anymore, see https://security.googleblog.com/2014/04/new-security-measures-will-affect-older.html for info.

and here's something i threw together to debug why it wasn't working on gmail...:

$user = '???';
$pass = '???';
$host = 'ssl://smtp.gmail.com';
// $host = 'ssl://email-smtp.us-east-1.amazonaws.com'; //Amazon SES
$port = 465;
$to = '???';
$from = '???';
$subject = "test";
$body = 'test<br/>test';

var_dump(smtp_mail2 ( $to, $from, $subject, $body, $user, $pass, $host, $port ));
function smtp_mail2($to, $from, $subject, $body, $user, $pass, $host, $port) {
	$message = implode ( "\r\n", array (
			'Subject: =?UTF-8?B?' . base64_encode ( $subject ) . '?=',
			'To: <' . $to . '>',
			'From: ' . $from,
			'MIME-Version: 1.0',
			'Content-Type: text/html; charset=utf-8',
			'Content-Transfer-Encoding: base64',
			"\r\n" . base64_encode ( $body )  // the (double) \r\n separate request headers from request body.
	) );
	$data = array (
			"EHLO " . parse_url ( $host, PHP_URL_HOST ),
			'AUTH LOGIN',
			base64_encode ( $user ),
			base64_encode ( $pass ),
			"MAIL FROM: <$from>",
			"RCPT TO: <$to>",
			'DATA',
			$message 
	);
	// $sock = fsockopen ( $host, $port, $errno, $errstr );
	$sslstuff = array (
			"ssl" => array (
					"verify_peer" => false,
					"verify_peer_name" => false 
				// "cafile" => "/path/to/bundle/cacert.pem",
				// "verify_peer"=> true,
				// "verify_peer_name"=> true,
			) 
	);
	$socket_write_all = function ($sock, $data) {
		$len = strlen ( $data );
		while ( $len > 0 ) {
			echo "writing...";
			$written = fwrite ( $sock, $data );
			if ($written === false) {
				throw new RuntimeException ( 'socket_write failed. errno: ' . socket_last_error ( $sock ) . '. error: ' . socket_strerror ( socket_last_error ( $sock ) ) );
			}
			$len -= $written;
			$data = substr ( $data, $written );
		}
		return; // all data written
	};
	$sock = stream_socket_client ( $host . ':' . $port, $errno, $errstr, 10, STREAM_CLIENT_CONNECT, stream_context_create ( $sslstuff ) );
	if (false === $sock) {
		throw new \RuntimeException ( 'failed to connect! errno: ' . $errno . '. errstr: ' . $errstr );
	}
	$debugMessageLog = array ();
	stream_set_blocking ( $sock, true );
	$welcomeMessage = fgets ( $sock );
	$debugMessageLog [] = array (
			'connect',
			$welcomeMessage 
	);
	// var_dump ( $welcomeMessage );
	foreach ( $data as $message ) {
		$socket_write_all ( $sock, $message . "\r\n" );
		$tmpFullResponse = '';
		while ( false !== ($tmpResponse = fgets ( $sock )) ) {
			var_dump ( $tmpResponse );
			$tmpFullResponse .= $tmpResponse;
		}
		$debugMessageLog [] = array (
				$message,
				$tmpFullResponse 
		);
		unset ( $tmpFullResponse, $tmpResponse, $message );
	}
	$socket_write_all ( $sock, "QUIT\r\n" );
	var_dump ( $debugMessageLog );
	return fclose ( $sock );

}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment