Create a gist now

Instantly share code, notes, and snippets.

Embed
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);
}
}
@charlyasap

This comment has been minimized.

Show comment
Hide comment
@charlyasap

charlyasap Nov 13, 2012

Very nice snippet and works fine.

Very nice snippet and works fine.

@charlyasap

This comment has been minimized.

Show comment
Hide comment
@charlyasap

charlyasap Nov 13, 2012

Can I use it in my projects?

Can I use it in my projects?

@Xeoncross

This comment has been minimized.

Show comment
Hide comment
@Xeoncross

Xeoncross Nov 15, 2012

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

Owner

Xeoncross commented Nov 15, 2012

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

@divinity76

This comment has been minimized.

Show comment
Hide comment
@divinity76

divinity76 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 );

}

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