368 lines
12 KiB
PHP
368 lines
12 KiB
PHP
<?php
|
|
/**
|
|
* KM_Mailer is a SMTP Class for PHP, Version 1.5
|
|
* created by KidMoses (Howard Walsh)
|
|
*
|
|
* This is a smiple SMTP class that supports secure login
|
|
* through TLS or SSL connections. Can be used to send email
|
|
* through GMail for example.
|
|
*
|
|
* Email can be sent as either plain text, html text or a
|
|
* combination of both.
|
|
|
|
* Please send support questions to support@kidmoses.com
|
|
*
|
|
* INSTRUCTIONS
|
|
* Create an instance of the class with a call to :
|
|
* $mail = new KM_Mailer(server, port, username=null, password=null, secure=null);
|
|
*
|
|
* server : the name of the server you are connecting to
|
|
* port : the port number to use (typically 25, 465 or 587)
|
|
* username : your username needed to log into the server
|
|
* password : the password needed to log into the server
|
|
* secure : can be tls, ssl or none
|
|
*
|
|
* You can check if your have successfully logged in by checking $mail->isLogin
|
|
*
|
|
* Once the instance is created, you can send mail by calling :
|
|
* $mail->send(from, to, subject, body, headers = optional);
|
|
*
|
|
* from : sender's email address (myname@mydomain.com OR MyName <myname@mydomain.com>)
|
|
* to : recipient's email address (ie: yourname@yourdomain.com OR YourName <yourname@yourdomain.com>)
|
|
* subject : email subject
|
|
* body : email message body, usually in HTML format
|
|
* headers : any special headers required
|
|
*
|
|
* See example.php for more tips
|
|
*
|
|
* In this version you can also add multiple recipents, carbon-copies(CC), blind-copies(BCC) and attachments
|
|
* For example:
|
|
* $mail->addRecipient("yourname@yourdomain.com");
|
|
* $mail->addCC("yourname@yourdomain.com");
|
|
* $mail->addBCC("yourname@yourdomain.com");
|
|
* $mail->addAttachment("pathToAttachment");
|
|
*
|
|
* To clear recipients and attachments use:
|
|
* $mail->clearRecipients();
|
|
* $mail->clearCC();
|
|
* $mail->clearBCC();
|
|
* $mail->clearAttachments();
|
|
*
|
|
**/
|
|
|
|
/**
|
|
* Copyright (c) 2011, Howard Walsh, KidMoses.com.
|
|
* All rights reserved.
|
|
*
|
|
* Redistribution and use in source and binary forms, with or without
|
|
* modification, are permitted provided that the following conditions
|
|
* are met:
|
|
*
|
|
* * Redistributions of source code must retain the above copyright
|
|
* notice, this list of conditions and the following disclaimer.
|
|
*
|
|
* * Redistributions in binary form must reproduce the above
|
|
* copyright notice, this list of conditions and the following
|
|
* disclaimer in the documentation and/or other materials provided
|
|
* with the distribution.
|
|
*
|
|
* * Neither the names of Howard Walsh or KidMoses.com, nor
|
|
* the names of its contributors may be used to endorse or promote
|
|
* products derived from this software without specific prior
|
|
* written permission.
|
|
*
|
|
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
|
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
|
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
|
|
* FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
|
|
* COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
|
|
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
|
|
* BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
|
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
|
|
* CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
|
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY
|
|
* WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY
|
|
* OF SUCH DAMAGE.
|
|
**/
|
|
|
|
|
|
//include("strip_html_tags.php"); /* this script provided by David R. Nadeau, NadeauSoftware.com */
|
|
|
|
class KM_Mailer {
|
|
public $server;
|
|
public $port;
|
|
public $username;
|
|
public $password;
|
|
public $secure; /* can be tls, ssl, or none */
|
|
|
|
public $charset = "\"utf-8\""; /* included double quotes on purpose */
|
|
public $contentType = "multipart/mixed"; /* can be set to: text/plain, text/html, multipart/mixed */
|
|
public $transferEncodeing = "base64"; /* or 8-bit */
|
|
public $altBody = "";
|
|
public $isLogin = false;
|
|
public $recipients = array();
|
|
public $cc = array();
|
|
public $bcc = array();
|
|
public $attachments = array();
|
|
|
|
private $conn;
|
|
private $newline = "\r\n";
|
|
private $localhost = 'localhost';
|
|
private $timeout = '60';
|
|
private $debug = false;
|
|
|
|
public function __construct($server, $port, $username=null, $password=null, $secure=null) {
|
|
$this->server = $server;
|
|
$this->port = $port;
|
|
$this->username = $username;
|
|
$this->password = $password;
|
|
$this->secure = $secure;
|
|
|
|
if(!$this->connect()) return;
|
|
if(!$this->auth()) return;
|
|
$this->isLogin = true;
|
|
return;
|
|
}
|
|
|
|
/* Connect to the server */
|
|
private function connect() {
|
|
if(strtolower(trim($this->secure)) == 'ssl') {
|
|
$this->server = 'ssl://' . $this->server;
|
|
}
|
|
$this->conn = fsockopen($this->server, $this->port, $errno, $errstr, $this->timeout);
|
|
if (substr($this->getServerResponse(),0,3)!='220') { return false; }
|
|
return true;
|
|
}
|
|
|
|
/* sign in / authenicate */
|
|
private function auth() {
|
|
fputs($this->conn, 'HELO ' . $this->localhost . $this->newline);
|
|
$this->getServerResponse();
|
|
if(strtolower(trim($this->secure)) == 'tls') {
|
|
fputs($this->conn, 'STARTTLS' . $this->newline);
|
|
if (substr($this->getServerResponse(),0,3)!='220') { return false; }
|
|
|
|
|
|
stream_socket_enable_crypto($this->conn, true, STREAM_CRYPTO_METHOD_TLS_CLIENT);
|
|
fputs($this->conn, 'HELO ' . $this->localhost . $this->newline);
|
|
if (substr($this->getServerResponse(),0,3)!='250') { return false; }
|
|
|
|
}
|
|
if($this->server != 'localhost') {
|
|
fputs($this->conn, 'AUTH LOGIN' . $this->newline);
|
|
|
|
if (substr($this->getServerResponse(),0,3)!='334') { return false; }
|
|
|
|
fputs($this->conn, base64_encode($this->username) . $this->newline);
|
|
if (substr($this->getServerResponse(),0,3)!='334') { return false; }
|
|
|
|
fputs($this->conn, base64_encode($this->password) . $this->newline);
|
|
if (substr($this->getServerResponse(),0,3)!='235') { return false; }
|
|
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
/* send the email message */
|
|
public function send($from, $to, $subject, $message, $headers=null) {
|
|
/* set up the headers and message body with attachments if necessary */
|
|
$email = "Date: " . date("D, j M Y G:i:s") . " +0300" . $this->newline;
|
|
$email .= "From: $from" . $this->newline;
|
|
$email .= "Reply-To: $from" . $this->newline;
|
|
$email .= $this->setRecipients($to);
|
|
|
|
if ($headers != null) { $email .= $headers . $this->newline; }
|
|
|
|
$email .= "Subject: $subject" . $this->newline;
|
|
$email .= "MIME-Version: 1.0" . $this->newline;
|
|
if($this->contentType == "multipart/mixed") {
|
|
$boundary = $this->generateBoundary();
|
|
$message = $this->multipartMessage($message,$boundary);
|
|
$email .= "Content-Type: $this->contentType;" . $this->newline;
|
|
$email .= " boundary=\"$boundary\"";
|
|
} else {
|
|
$email .= "Content-Type: $this->contentType; charset=$this->charset";
|
|
}
|
|
$email .= $this->newline . $this->newline . $message . $this->newline;
|
|
$email .= "." . $this->newline;
|
|
|
|
/* set up the server commands and send */
|
|
fputs($this->conn, 'MAIL FROM: <'. $this->getMailAddr($from) .'>'. $this->newline);
|
|
$this->getServerResponse();
|
|
|
|
if(!$to=='') {
|
|
fputs($this->conn, 'RCPT TO: <'. $this->getMailAddr($to) .'>' . $this->newline);
|
|
$this->getServerResponse();
|
|
}
|
|
|
|
|
|
$this->sendRecipients($this->recipients);
|
|
$this->sendRecipients($this->cc);
|
|
$this->sendRecipients($this->bcc);
|
|
|
|
fputs($this->conn, 'DATA'. $this->newline);
|
|
$this->getServerResponse();
|
|
fputs($this->conn, $email); /* transmit the entire email here */
|
|
|
|
if (substr($this->getServerResponse(),0,3)!='250') { return false; }
|
|
|
|
|
|
return true;
|
|
}
|
|
|
|
private function setRecipients($to) { /* assumes there is at least one recipient */
|
|
$r = 'To: ';
|
|
if(!($to=='')) { $r .= $to . ','; }
|
|
if(count($this->recipients)>0) {
|
|
for($i=0;$i<count($this->recipients);$i++) {
|
|
$r .= $this->recipients[$i] . ',';
|
|
}
|
|
}
|
|
$r = substr($r,0,-1) . $this->newline; /* strip last comma */;
|
|
if(count($this->cc)>0) { /* now add in any CCs */
|
|
$r .= 'CC: ';
|
|
for($i=0;$i<count($this->cc);$i++) {
|
|
$r .= $this->cc[$i] . ',';
|
|
}
|
|
$r = substr($r,0,-1) . $this->newline; /* strip last comma */
|
|
}
|
|
return $r;
|
|
}
|
|
|
|
private function sendRecipients($r) {
|
|
if(empty($r)) { return; }
|
|
for($i=0;$i<count($r);$i++) {
|
|
fputs($this->conn, 'RCPT TO: <'. $this->getMailAddr($r[$i]) .'>'. $this->newline);
|
|
$this->getServerResponse();
|
|
}
|
|
}
|
|
|
|
public function addRecipient($recipient) {
|
|
$this->recipients[] = $recipient;
|
|
}
|
|
|
|
public function clearRecipients() {
|
|
unset($this->recipients);
|
|
$this->recipients = array();
|
|
}
|
|
|
|
public function addCC($c) {
|
|
$this->cc[] = $c;
|
|
}
|
|
|
|
public function clearCC() {
|
|
unset($this->cc);
|
|
$this->cc = array();
|
|
}
|
|
|
|
public function addBCC($bc) {
|
|
$this->bcc[] = $bc;
|
|
}
|
|
|
|
public function clearBCC() {
|
|
unset($this->bcc);
|
|
$this->bcc = array();
|
|
}
|
|
|
|
public function addAttachment($filePath) {
|
|
$this->attachments[] = $filePath;
|
|
}
|
|
|
|
public function clearAttachments() {
|
|
unset($this->attachments);
|
|
$this->attachments = array();
|
|
}
|
|
|
|
/* Quit and disconnect */
|
|
function __destruct() {
|
|
fputs($this->conn, 'QUIT' . $this->newline);
|
|
$this->getServerResponse();
|
|
fclose($this->conn);
|
|
}
|
|
|
|
/* private functions used internally */
|
|
private function getServerResponse() {
|
|
$data="";
|
|
while($str = fgets($this->conn,4096)) {
|
|
$data .= $str;
|
|
if(substr($str,3,1) == " ") { break; }
|
|
}
|
|
if($this->debug) echo $data . "<br>";
|
|
return $data;
|
|
}
|
|
|
|
private function getMailAddr($emailaddr) {
|
|
$addr = $emailaddr;
|
|
$strSpace = strrpos($emailaddr,' ');
|
|
if($strSpace > 0) {
|
|
$addr= substr($emailaddr,$strSpace+1);
|
|
$addr = str_replace("<","",$addr);
|
|
$addr = str_replace(">","",$addr);
|
|
}
|
|
return $addr;
|
|
}
|
|
|
|
private function randID($len) {
|
|
$index = "abcdefghijklmnopqrstuvwxyz0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ";
|
|
$out = "";
|
|
for ($t=0; $t<$len;$t++) {
|
|
$r = rand(0,61);
|
|
$out = $out . substr($index,$r,1);
|
|
}
|
|
return $out;
|
|
}
|
|
|
|
private function generateBoundary() {
|
|
$boundary = "--=_NextPart_000_";
|
|
$boundary .= $this->randID(4) . "_";
|
|
$boundary .= $this->randID(8) . ".";
|
|
$boundary .= $this->randID(8);
|
|
return $boundary;
|
|
}
|
|
|
|
private function multipartMessage($htmlpart,$boundary) {
|
|
if($this->altBody == "") { $this->altBody = strip_tags($htmlpart); }
|
|
$altBoundary = $this->generateBoundary();
|
|
ob_start(); //Turn on output buffering
|
|
$parts = "This is a multi-part message in MIME format." . $this->newline . $this->newline;
|
|
$parts .= "--" . $boundary . $this->newline;
|
|
|
|
$parts .= "Content-Type: multipart/alternative;" . $this->newline;
|
|
$parts .= " boundary=\"$altBoundary\"" . $this->newline . $this->newline;
|
|
|
|
$parts .= "--" . $altBoundary . $this->newline;
|
|
$parts .= "Content-Type: text/plain; charset=$this->charset" . $this->newline;
|
|
$parts .= "Content-Transfer-Encoding: $this->transferEncodeing" . $this->newline . $this->newline;
|
|
$parts .= chunk_split(base64_encode($this->altBody)) . $this->newline . $this->newline;
|
|
|
|
$parts .= "--" . $altBoundary . $this->newline;
|
|
$parts .= "Content-Type: text/html; charset=$this->charset" . $this->newline;
|
|
$parts .= "Content-Transfer-Encoding: $this->transferEncodeing" . $this->newline . $this->newline;
|
|
$parts .= chunk_split(base64_encode($htmlpart)) . $this->newline . $this->newline;
|
|
|
|
$parts .= "--" . $altBoundary . "--" . $this->newline . $this->newline;
|
|
|
|
if(count($this->attachments) > 0) {
|
|
for($i=0;$i<count($this->attachments);$i++) {
|
|
$attachment = chunk_split(base64_encode(file_get_contents($this->attachments[$i])));
|
|
$filename = basename($this->attachments[$i]);
|
|
$ext = pathinfo($filename, PATHINFO_EXTENSION);
|
|
$parts .= "--" . $boundary . $this->newline;
|
|
$parts .= "Content-Type: application/$ext; name=\"$filename\"" . $this->newline;
|
|
$parts .= "Content-Transfer-Encoding: base64" . $this->newline;
|
|
$parts .= "Content-Disposition: attachment; filename=\"$filename\"" . $this->newline . $this->newline;
|
|
$parts .= $attachment . $this->newline;
|
|
}
|
|
}
|
|
|
|
$parts .= "--" . $boundary . "--";
|
|
|
|
$message = ob_get_clean(); //Turn off output buffering
|
|
return $parts;
|
|
}
|
|
|
|
}
|
|
|
|
?>
|