 |
LXXIX. Mail 邮件函数
要使邮件函数可用,PHP 必须在编译时能够访问
sendmail 程序。如果使用其它的邮件程序例如 qmail
或 postfix,确保使用了与其相应的 sendmail 替代程序。PHP 首先会在系统的
PATH 中搜索
sendmail,接着按以下顺序搜索:/usr/bin:/usr/sbin:/usr/etc:/etc:/usr/ucblib:/usr/lib。强烈建议在
PATH 中能够找到 sendmail。另外,编译 PHP 的用户必须能够访问 sendmail 程序。
本扩展模块作为 PHP 内核的一部分,无需安装即可使用。 这些函数的行为受 php.ini 的影响。
表 1. Mail 配置选项 | 名称 | 默认值 | 可修改范围 | 更新记录 |
|---|
| SMTP | "localhost" | PHP_INI_ALL | | | smtp_port | "25" | PHP_INI_ALL | 自 PHP 4.3.0 起可用 | | sendmail_from | NULL | PHP_INI_ALL | | | sendmail_path | NULL | PHP_INI_SYSTEM | |
有关 PHP_INI_* 常量进一步的细节与定义参见 附录 H。
以下是配置选项的简要解释。
SMTP
string
仅用于 Windows:PHP 在 mail() 函数中用来发送邮件的
SMTP 服务器的主机名称或者 IP 地址。
smtp_port
int
仅用于 Windows:SMTP 服务器的端口号,默认为 25。自
PHP 4.3.0 起可用。
sendmail_from
string
在 Windows 下用 PHP 发送邮件时的“From:”邮件地址的值。该选项同时设置了
“Return-Path:”头。
sendmail_path
string
sendmail 程序的路径,通常为
/usr/sbin/sendmail 或
/usr/lib/sendmail。configure
脚本会尝试找到该程序并设定为默认值,但是如果失败的话,可以在这里设定。
不使用 sendmail 的系统应将此指令设定为其邮件系统提供的
sendmail 替代程序,如果有的话。例如,Qmail
用户通常可以设为
/var/qmail/bin/sendmail 或
/var/qmail/bin/qmail-inject。
qmail-inject 不需要任何选项就能正确处理邮件。
此指令也可用于 Windows。如果设定,smtp,smtp_port
和 sendmail_from 都被忽略并运行指定的命令。
rob at withoutsin dot com
26-Jun-2007 05:57
New and Improved - well for gmail users at least. Their SMTP responds differently than other MTA"s. Make sure to enable the pop mail in the gmail account settings first
function authgMail($from, $namefrom, $to, $nameto, $subject, $message)
{
/* your configuration here */
$smtpServer = "tls://smtp.gmail.com"; //does not accept STARTTLS
$port = "465"; // try 587 if this fails
$timeout = "45"; //typical timeout. try 45 for slow servers
$username = "yous@gmail.com"; //your gmail account
$password = "y0u4p@55"; //the pass for your gmail
$localhost = $_SERVER['REMOTE_ADDR']; //requires a real ip
$newLine = "\r\n"; //var just for newlines
/* you shouldn't need to mod anything else */
//connect to the host and port
$smtpConnect = fsockopen($smtpServer, $port, $errno, $errstr, $timeout);
echo $errstr." - ".$errno;
$smtpResponse = fgets($smtpConnect, 4096);
if(empty($smtpConnect))
{
$output = "Failed to connect: $smtpResponse";
echo $output;
return $output;
}
else
{
$logArray['connection'] = "Connected to: $smtpResponse";
echo "connection accepted<br>".$smtpResponse."<p />Continuing<p />";
}
//you have to say HELO again after TLS is started
fputs($smtpConnect, "HELO $localhost". $newLine);
$smtpResponse = fgets($smtpConnect, 4096);
$logArray['heloresponse2'] = "$smtpResponse";
//request for auth login
fputs($smtpConnect,"AUTH LOGIN" . $newLine);
$smtpResponse = fgets($smtpConnect, 4096);
$logArray['authrequest'] = "$smtpResponse";
//send the username
fputs($smtpConnect, base64_encode($username) . $newLine);
$smtpResponse = fgets($smtpConnect, 4096);
$logArray['authusername'] = "$smtpResponse";
//send the password
fputs($smtpConnect, base64_encode($password) . $newLine);
$smtpResponse = fgets($smtpConnect, 4096);
$logArray['authpassword'] = "$smtpResponse";
//email from
fputs($smtpConnect, "MAIL FROM: <$from>" . $newLine);
$smtpResponse = fgets($smtpConnect, 4096);
$logArray['mailfromresponse'] = "$smtpResponse";
//email to
fputs($smtpConnect, "RCPT TO: <$to>" . $newLine);
$smtpResponse = fgets($smtpConnect, 4096);
$logArray['mailtoresponse'] = "$smtpResponse";
//the email
fputs($smtpConnect, "DATA" . $newLine);
$smtpResponse = fgets($smtpConnect, 4096);
$logArray['data1response'] = "$smtpResponse";
//construct headers
$headers = "MIME-Version: 1.0" . $newLine;
$headers .= "Content-type: text/html; charset=iso-8859-1" . $newLine;
$headers .= "To: $nameto <$to>" . $newLine;
$headers .= "From: $namefrom <$from>" . $newLine;
//observe the . after the newline, it signals the end of message
fputs($smtpConnect, "To: $to\r\nFrom: $from\r\nSubject: $subject\r\n$headers\r\n\r\n$message\r\n.\r\n");
$smtpResponse = fgets($smtpConnect, 4096);
$logArray['data2response'] = "$smtpResponse";
// say goodbye
fputs($smtpConnect,"QUIT" . $newLine);
$smtpResponse = fgets($smtpConnect, 4096);
$logArray['quitresponse'] = "$smtpResponse";
$logArray['quitcode'] = substr($smtpResponse,0,3);
fclose($smtpConnect);
//a return value of 221 in $retVal["quitcode"] is a success
return($logArray);
}
sevr at mail dot ru
21-Jun-2007 03:02
It is seems that quotes is needed in the header in charset param. Outlook can't define encoding without them.
$headers = "Content-Type: text/html; charset=\"windows-1251\"\r\n";
$headers .= "MIME-Version: 1.0 ";
rob at withoutsin dot com
12-Jun-2007 08:15
Having beaten my head against an MCSE for several days over my need for a mail form and his need for "heightened security for IIS" I finally managed to get a working authentication model for Exchange 2003. (note: this will ONLY relay mail to actual users of the Exchange server. i.e. registered email address)
<?
function authMail($from, $namefrom, $to, $nameto, $subject, $message)
{
/* your configuration here */
$smtpServer = "mail.yourdomain.com"; //ip accepted as well
$port = "25"; // should be 25 by default
$timeout = "30"; //typical timeout. try 45 for slow servers
$username = "webform"; //the login for your smtp
$password = "passhere"; //the pass for your smtp
$localhost = "127.0.0.1"; //this seems to work always
$newLine = "\r\n"; //var just for nelines in MS
$secure = 0; //change to 1 if you need a secure connect
/* you shouldn't need to mod anything else */
//connect to the host and port
$smtpConnect = fsockopen($smtpServer, $port, $errno, $errstr, $timeout);
$smtpResponse = fgets($smtpConnect, 4096);
if(empty($smtpConnect))
{
$output = "Failed to connect: $smtpResponse";
return $output;
}
else
{
$logArray['connection'] = "Connected to: $smtpResponse";
}
//say HELO to our little friend
fputs($smtpConnect, "HELO $localhost". $newLine);
$smtpResponse = fgets($smtpConnect, 4096);
$logArray['heloresponse'] = "$smtpResponse";
//start a tls session if needed
if($secure)
{
fputs($smtpConnect, "STARTTLS". $newLine);
$smtpResponse = fgets($smtpConnect, 4096);
$logArray['tlsresponse'] = "$smtpResponse";
//you have to say HELO again after TLS is started
fputs($smtpConnect, "HELO $localhost". $newLine);
$smtpResponse = fgets($smtpConnect, 4096);
$logArray['heloresponse2'] = "$smtpResponse";
}
//request for auth login
fputs($smtpConnect,"AUTH LOGIN" . $newLine);
$smtpResponse = fgets($smtpConnect, 4096);
$logArray['authrequest'] = "$smtpResponse";
//send the username
fputs($smtpConnect, base64_encode($username) . $newLine);
$smtpResponse = fgets($smtpConnect, 4096);
$logArray['authusername'] = "$smtpResponse";
//send the password
fputs($smtpConnect, base64_encode($password) . $newLine);
$smtpResponse = fgets($smtpConnect, 4096);
$logArray['authpassword'] = "$smtpResponse";
//email from
fputs($smtpConnect, "MAIL FROM: $from" . $newLine);
$smtpResponse = fgets($smtpConnect, 4096);
$logArray['mailfromresponse'] = "$smtpResponse";
//email to
fputs($smtpConnect, "RCPT TO: $to" . $newLine);
$smtpResponse = fgets($smtpConnect, 4096);
$logArray['mailtoresponse'] = "$smtpResponse";
//the email
fputs($smtpConnect, "DATA" . $newLine);
$smtpResponse = fgets($smtpConnect, 4096);
$logArray['data1response'] = "$smtpResponse";
//construct headers
$headers = "MIME-Version: 1.0" . $newLine;
$headers .= "Content-type: text/html; charset=iso-8859-1" . $newLine;
$headers .= "To: $nameto <$to>" . $newLine;
$headers .= "From: $namefrom <$from>" . $newLine;
//observe the . after the newline, it signals the end of message
fputs($smtpConnect, "To: $to\r\nFrom: $from\r\nSubject: $subject\r\n$headers\r\n\r\n$message\r\n.\r\n");
$smtpResponse = fgets($smtpConnect, 4096);
$logArray['data2response'] = "$smtpResponse";
// say goodbye
fputs($smtpConnect,"QUIT" . $newLine);
$smtpResponse = fgets($smtpConnect, 4096);
$logArray['quitresponse'] = "$smtpResponse";
$logArray['quitcode'] = substr($smtpResponse,0,3);
fclose($smtpConnect);
//a return value of 221 in $retVal["quitcode"] is a success
return($logArray);
}
?>
Obviously this function can be expanded upon, and adding attachments should be no real issue based on code found on this page. For me the authentication was the goal; while I had seen many scripts offering it, none seemed to work. I hope this helps someone out there defeat their evil MCSE counterpart
mail [ at ] wietse [ dot ] com
11-Jun-2007 07:35
[ THIS NOTE IS FOR MY POST ABOUT THE SEND_MAIL() FUNCTION ]
In addition to the already posted PHP Mail-functions, I decided there wasn't one that fitted all my needs, so I wrote my own. I have tested it, and I use it at a Windows 2000 server, but I don't think it won't function at *nix.
Usage:
send_mail(string $MailTo, string $SenderName, string $SenderMail, string $Subject, string-or-path $Mailcontent [, string $Attachment ] [, string $Servername ] [, string $nohtml])
The function returns true or false, depending on if the E-mail has been sent succesfully.
Note 1: $Mailcontent can be a string OR a path to a file.
Note 2: Function works without attachment too
Note 3: Function works to Hotmail
Note 4: Function needs PHP module [ mime_magic ] to detect attachment-type!
mail [ at ] wietse [ dot ] com
11-Jun-2007 07:34
<?php
function send_mail($MailTo = "", $SenderName = "Sender", $SenderMail = "no@reply.error", $Subject = "", $Mailcontent = "no.file", $Attachment = "no.file", $Servername = "PHPMAILSERVER", $nohtml = "[ This message should be viewed in HTML. This is a degraded version! ]"){
if(strtoupper(substr(PHP_OS,0,3)=='WIN')){
$eol="\r\n";
$sol="\n";
}elseif(strtoupper(substr(PHP_OS,0,3)=='MAC')){
$eol="\r";
}else{
$eol="\n";
}
if(!isset($sol)){
$sol = $eol;
}
$Momentn = mktime().".".md5(rand(1000,9999));
$f_name = $Attachment;
$handle = fopen($f_name, 'rb');
$f_contents = @fread($handle, filesize($f_name));
$f_contents = @base64_encode($f_contents);
if($handle){
$sendfile = true;
if(ini_get('mime_magic.debug')){
$Bestype = @mime_content_type($Attachment);
}else{
$Bestype = 'application/octet-stream';
}
if(!$Bestype){
$Bestype = 'application/octet-stream';
}
$file_realname = explode("/", $Attachment);
$file_realname = $file_realname[count($file_realname)-1];
$file_realname = explode("\\", $file_realname);
$file_realname = $file_realname[count($file_realname)-1];
}
@fclose($handle);
$Mailcontentstri = explode($sol, $Mailcontent);
$Mailcontentstrip = strip_tags($Mailcontentstri[0]);
if(@file_exists($Mailcontentstrip)){
ob_start();
if(require($Mailcontent)){
$body = ob_get_contents();
}
ob_end_clean();
}else{
if(count($Mailcontentstri) < 2){
$body = "Error loading file!";
$error = true;
}else{
$body = $Mailcontent;
}
}
$Textmsg = eregi_replace("<br(.{0,2})>", $eol, $body);
$Textmsg = eregi_replace("</p>", $eol, $Textmsg);
$Textmsg = strip_tags($Textmsg);
$Textmsg = $nohtml.$eol.$eol.$Textmsg;
$headers .= 'To: '.$MailTo.' <'.$MailTo.'>'.$eol;
$headers .= 'From: '.$SenderName.' <'.$SenderMail.'>'.$eol;
$headers .= "Message-ID: <".$Momentn."@".$Servername.">".$eol;
$headers .= 'Date: '.date("r").$eol;
$headers .= 'Sender-IP: '.$_SERVER["REMOTE_ADDR"].$eol;
$headers .= 'X-Mailser: iPublications Adv.PHP Mailer 1.6'.$eol;
$headers .= 'MIME-Version: 1.0'.$eol;
$bndp = md5(time()).rand(1000,9999);
$headers .= "Content-Type: multipart/mixed; $eol boundary=\"".$bndp."\"".$eol.$eol;
$msg = "This is a multi-part message in MIME format.".$eol.$eol;
$msg .= "--".$bndp.$eol;
$bnd = md5(time()).rand(1000,9999);
$msg .= "Content-Type: multipart/alternative; $eol boundary=\"".$bnd."\"".$eol.$eol;
$msg .= "--".$bnd.$eol;
$msg .= "Content-Type: text/plain; charset=iso-8859-1".$eol;
$msg .= "Content-Transfer-Encoding: 8bit".$eol.$eol;
$msg .= $Textmsg.$eol;
$msg .= "--".$bnd.$eol;
$msg .= "Content-Type: text/html; charset=iso-8859-1".$eol;
$msg .= "Content-Transfer-Encoding: 8-bit".$eol.$eol;
$msg .= $body.$eol;
$msg .= "--".$bnd."--".$eol.$eol;
if(isset($sendfile)){
$msg .= "--".$bndp.$eol;
$msg .= "Content-Type: $Bestype; name=\"".$file_realname."\"".$eol;
$msg .= "Content-Transfer-Encoding: base64".$eol;
$msg .= "Content-Disposition: attachment;".$eol;
$msg .= " filename=\"".$file_realname."\"".$eol.$eol;
$f_contents = chunk_split($f_contents);
$msg .= $f_contents.$eol;
}
$msg .= "--".$bndp."--";
if(!isset($error)){
if(@mail($MailTo, $Subject, $msg, $headers)){
return true;
}else{
return false;
}
}else{
return false;
}
}
?>
Pop
20-May-2007 02:03
If sendmail on your linux server is configured with options:
sendmail -t -i
you may have problems sending mail if you put something like this in your header
<?
$headers .= "Return-Path: MyName <myname@myhost.com> /n";
?>
nstead use
<?
$headers .= "Reply-To: MyName <myname@myhost.com> /n";
?>
Geoff in Montreal
01-May-2007 10:07
Here is a PHP Mail Multipart/Alternative (Plain Text and HTML) code for *nix servers (Unix Like Servers)... if you are hosted on a windows server, simply replace all "\n" or "\n\n" in the below code to "\r\n" or "\r\n\r\n" respectively.
This code is for anyone who has already written an HTML page for their PHP mail... there are several PHP > HTML free translators on the internet. You may use one of them to translate your HTML code to PHP to insert into the following code. All there needs to change is to place a backslash before any quotations (EX: ... confirm that \"Our Company\" has ...), and to end each line with a newline character (EX: \n )...
This code method has been successfully tested with Apple Mail, Microsoft Outlook, G-Mail, and Yahoo Mail. I hope this helps out anyone that is writing a multipart/alternative PHP mailer script.
<?php
# -=-=-=- PHP FORM VARIABLES (add as many as you would like)
$name = $_POST["name"];
$email = $_POST["email"];
$invoicetotal = $_POST["invoicetotal"];
# -=-=-=- MIME BOUNDARY
$mime_boundary = "----Your_Company_Name----".md5(time());
# -=-=-=- MAIL HEADERS
$to = "$email";
$subject = "This text will display in the email's Subject Field";
$headers = "From: Our Company <company@ourcompany.com>\n";
$headers .= "Reply-To: Our Company <company@ourcompany.com>\n";
$headers .= "MIME-Version: 1.0\n";
$headers .= "Content-Type: multipart/alternative; boundary=\"$mime_boundary\"\n";
# -=-=-=- TEXT EMAIL PART
$message = "--$mime_boundary\n";
$message .= "Content-Type: text/plain; charset=UTF-8\n";
$message .= "Content-Transfer-Encoding: 8bit\n\n";
$message .= "$name:\n\n";
$message .= "This email is to confirm that \"Our Company\" has received your order.\n";
$message .= "Please send payment of $invoicetotal to our company address.\n\n";
$message .= "Thank You.\n\n";
# -=-=-=- HTML EMAIL PART
$message .= "--$mime_boundary\n";
$message .= "Content-Type: text/html; charset=UTF-8\n";
$message .= "Content-Transfer-Encoding: 8bit\n\n";
$message .= "<html>\n";
$message .= "<body style=\"font-family:Verdana, Verdana, Geneva, sans-serif; font-size:14px; color:#666666;\">\n";
$message .= "$name:<br>\n";
$message .= "<br>\n";
$message .= "This email is to confirm that \"Our Company\" has received your order.<br>\n";
$message .= "Please send payment of $invoicetotal to our company address.<br>\n\n";
$message .= "<br>\n";
$message .= "Thank You.<br>\n\n";
$message .= "</body>\n";
$message .= "</html>\n";
# -=-=-=- FINAL BOUNDARY
$message .= "--$mime_boundary--\n\n";
# -=-=-=- SEND MAIL
$mail_sent = @mail( $to, $subject, $message, $headers );
echo $mail_sent ? "Mail sent" : "Mail failed";
?>
Geoff Montreal
30-Apr-2007 04:29
i strongly feel that internet site developers should exclusively use UTF-8 text encoding / character setting over ISO-8859-1... UTF-8 is universal and will display all characters as they were meant to be displayed, whereas ISO-8859-1 is prone to garbled text.
<?php
$message .= "Content-Type: text/plain; charset=UTF-8\n";
?>
~ and/or ~
<?php
$message .= "Content-Type: text/html; charset=UTF-8\n";
?>
note: above code for *nix servers.
mark at markkahn dot com
06-Apr-2007 03:54
i tried out 3 different scripts, and played with them for a few hours. Ugh.
Max Howell's mxcl mail function worked right off the bat - attachments, and body. using RH + php 4.4.
thanks max!
grass t leht dot ee
20-Mar-2007 10:07
something that worked for my outlook express...
dnx 4 your code "nielsvandenberge at hotmail dot com
"
but
if you just swich the text part into first and attachment part into second place, Outlook Express 6 reads it just fine
otherwise it creates a textfile of the text content....
admin at seoandstuff dot com
15-Mar-2007 04:25
I just spent a few hours working on getting a simple html formatted email to work on outlook. This is the end result:
<?php
$body="<em>HTML</em> formatted <strong>Message</strong";
$headers = "From: info@example.com \r\n";
$headers.= "Content-Type: text/html; charset=ISO-8859-1 ";
$headers .= "MIME-Version: 1.0 ";
/*notice there aren't any \r\n after the second two header additions. This is what made this version work correctly*/
mail("john@example.com", "An HTML Message", $body, $headers);
?>
br at winf dot at
27-Feb-2007 12:07
The example function by nielsvandenberge at hotmail dot com is nice, but some Mail Programs (e.g. Outlook Express, etc) do have problems and do not display any text or html of the mailbody - only as a separate attachment.
The main problem is that the multipart/alternative part is not bounded correctly (a problem that Outlook and other newer mailers seem to ignore). To make the function compatible to older/standard mail-programs simply add a second mime boundary, which marks the bounds of the alternative parts:
<?
$mime_boundary_2 = "1_".$mime_boundary;
$msg .= "Content-Type: multipart/alternative; boundary=\"".$mime_boundary_2."\"".$eol;
# Text Version
$msg .= "--".$mime_boundary_2.$eol;
$msg .= "Content-Type: text/plain; charset=iso-8859-1".$eol;
$msg .= "Content-Transfer-Encoding: 8bit".$eol.$eol;
$msg .= strip_tags(str_replace("<br>", "\n", $body)).$eol.$eol;
# HTML Version
$msg .= "--".$mime_boundary_2.$eol;
$msg .= "Content-Type: text/html; charset=iso-8859-1".$eol;
$msg .= "Content-Transfer-Encoding: 8bit".$eol.$eol;
$msg .= $body.$eol.$eol;
# New Subboundary Finished
$msg .= "--".$mime_boundary_2."--".$eol.$eol;
# Top-Boundary Finished
$msg .= "--".$mime_boundary."--".$eol.$eol;
?>
The above snippet also corrects the missing second eol after Content-Transfer-Encoding: 8bit.
jo at camindo de
06-Feb-2007 09:26
If you have programmed headers do not adopt post-values unfiltered!!
Often used in scripts, and often abused by spam mailings:
$headers = "From: {$email}";
If somebody posts email="me@example.com
Bcc:someone1@example.com,someoneelse@example.com,..."
(with linebreak behind me@example.com)
You get following headers:
From: me@example.com
Bcc:someone1@example.com,someoneelse@example.com,...
Max Howell
02-Feb-2007 04:54
I find this a useful function, and it's a lot easier to read and edit than the proceeding set. Many thanks to the proceeding set though, since they taught me how to do it!
<?php
function mxcl_mail( $subject, $message )
{
ob_start();
print_r( $GLOBALS );
$teh_globals = chunk_split( base64_encode( ob_get_clean() ) ); // base 64 encode
$date = date( 'r' );
$phpversion = phpversion();
$boundary = md5( time() );
$filename = '$GLOBALS.txt';
$headers = <<<END
From: $_SERVER[PHP_SELF] <php@$_SERVER[SERVER_NAME]>
Date: $date
X-Mailer: PHP v$phpversion
MIME-Version: 1.0
Content-Type: multipart/related; boundary="$boundary"
END;
$message = <<<END
--$boundary
Content-Type: text/plain; charset="iso-9959-1"
Content-Transfer-Encoding: 7bit
$message
--$boundary
Content-Type: octet-stream; name="$filename"
Content-Disposition: attachment; filename="$filename"
Content-Transfer-Encoding: base64
$teh_globals
--$boundary--
END;
mail( 'webmaster@example.com', $subject, $message, $headers );
}
?>
pbglez at hotmail dot com
30-Jan-2007 11:59
I think the easiest way to make correct attachments is checking The Official MIME Specification: http://www.hunnysoft.com/mime/ (Of course it isnt the only web page where you can find it ).
I found there an example than truly helped me to make correct attachments:
Appendix A -- A Complex Multipart Example
What follows is the outline of a complex multipart message. This
message contains five parts that are to be displayed serially: two
introductory plain text objects, an embedded multipart message, a
text/enriched object, and a closing encapsulated text message in a
non-ASCII character set. The embedded multipart message itself
contains two objects to be displayed in parallel, a picture and an
audio fragment.
MIME-Version: 1.0
From: Nathaniel Borenstein <nsb@nsb.fv.com>
To: Ned Freed <ned@innosoft.com>
Date: Fri, 07 Oct 1994 16:15:05 -0700 (PDT)
Subject: A multipart example
Content-Type: multipart/mixed;
boundary=unique-boundary-1
This is the preamble area of a multipart message.
Mail readers that understand multipart format
should ignore this preamble.
If you are reading this text, you might want to
consider changing to a mail reader that understands
how to properly display multipart messages.
--unique-boundary-1
... Some text appears here ...
[Note that the blank between the boundary and the start
of the text in this part means no header fields were
given and this is text in the US-ASCII character set.
It could have been done with explicit typing as in the
next part.]
--unique-boundary-1
Content-type: text/plain; charset=US-ASCII
This could have been part of the previous part, but
illustrates explicit versus implicit typing of body
parts.
--unique-boundary-1
Content-Type: multipart/parallel; boundary=unique-boundary-2
--unique-boundary-2
Content-Type: audio/basic
Content-Transfer-Encoding: base64
... base64-encoded 8000 Hz single-channel
mu-law-format audio data goes here ...
--unique-boundary-2
Content-Type: image/jpeg
Content-Transfer-Encoding: base64
... base64-encoded image data goes here ...
--unique-boundary-2--
--unique-boundary-1
Content-type: text/enriched
This is <bold><italic>enriched.</italic></bold>
<smaller>as defined in RFC 1896</smaller>
Isn't it
<bigger><bigger>cool?</bigger></bigger>
--unique-boundary-1
Content-Type: message/rfc822
From: (mailbox in US-ASCII)
To: (address in US-ASCII)
Subject: (subject in US-ASCII)
Content-Type: Text/plain; charset=ISO-8859-1
Content-Transfer-Encoding: Quoted-printable
... Additional text in ISO-8859-1 goes here ...
--unique-boundary-1--
Say_Ten
16-Jan-2007 10:45
Nice example script, although please note that:
$msg .= "Content-Transfer-Encoding: 8bit".$eol;
Should be:
$msg .= "Content-Transfer-Encoding: 8bit".$eol.$eol;
Francesco Piraneo G.
09-Jan-2007 01:52
Please note that the 'sendmail_from' parameter is used also on php running under linux, not only under Windows as stated on the documentation.
Webmail services and some spam washer software kill messages without the "From" field properly set.
Try the following:
ini_set(sendmail_from,$fromaddress); // the INI lines are to force the From Address to be used !
mail($emailaddress, $emailsubject, $msg, $headers);
...as correctly reported by nielsvandenberge at hotmail dot com.
For further info: fpiraneo at gmail dot com
nielsvandenberge at hotmail dot com
09-Jan-2007 10:44
I edited the code of genius Jon (thank you!) a bit and made an easy function to send multiple attachments with one e-mail. I stripped the HTML tags for the text-version, but haven't tested that.
The attachments variable of the function is a 2-dimensional array which should contain the keys "file" and "content_type".
I tested it with MS Outlook.
<?php
function send_mail($emailaddress, $fromaddress, $emailsubject, $body, $attachments=false)
{
$eol="\r\n";
$mime_boundary=md5(time());
# Common Headers
$headers .= 'From: MyName<'.$fromaddress.'>'.$eol;
$headers .= 'Reply-To: MyName<'.$fromaddress.'>'.$eol;
$headers .= 'Return-Path: MyName<'.$fromaddress.'>'.$eol; // these two to set reply address
$headers .= "Message-ID: <".$now." TheSystem@".$_SERVER['SERVER_NAME'].">".$eol;
$headers .= "X-Mailer: PHP v".phpversion().$eol; // These two to help avoid spam-filters
# Boundry for marking the split & Multitype Headers
$headers .= 'MIME-Version: 1.0'.$eol;
$headers .= "Content-Type: multipart/related; boundary=\"".$mime_boundary."\"".$eol;
$msg = "";
if ($attachments !== false)
{
for($i=0; $i < count($attachments); $i++)
{
if (is_file($attachments[$i]["file"]))
{
# File for Attachment
$file_name = substr($attachments[$i]["file"], (strrpos($attachments[$i]["file"], "/")+1));
$handle=fopen($attachments[$i]["file"], 'rb');
$f_contents=fread($handle, filesize($attachments[$i]["file"]));
$f_contents=chunk_split(base64_encode($f_contents)); //Encode The Data For Transition using base64_encode();
fclose($handle);
# Attachment
$msg .= "--".$mime_boundary.$eol;
$msg .= "Content-Type: ".$attachments[$i]["content_type"]."; name=\"".$file_name."\"".$eol;
$msg .= "Content-Transfer-Encoding: base64".$eol;
$msg .= "Content-Disposition: attachment; filename=\"".$file_name."\"".$eol.$eol; // !! This line needs TWO end of lines !! IMPORTANT !!
$msg .= $f_contents.$eol.$eol;
}
}
}
# Setup for text OR html
$msg .= "Content-Type: multipart/alternative".$eol;
# Text Version
$msg .= "--".$mime_boundary.$eol;
$msg .= "Content-Type: text/plain; charset=iso-8859-1".$eol;
$msg .= "Content-Transfer-Encoding: 8bit".$eol;
$msg .= strip_tags(str_replace("<br>", "\n", $body)).$eol.$eol;
# HTML Version
$msg .= "--".$mime_boundary.$eol;
$msg .= "Content-Type: text/html; charset=iso-8859-1".$eol;
$msg .= "Content-Transfer-Encoding: 8bit".$eol;
$msg .= $body.$eol.$eol;
# Finished
$msg .= "--".$mime_boundary."--".$eol.$eol; // finish with two eol's for better security. see Injection.
# SEND THE EMAIL
ini_set(sendmail_from,$fromaddress); // the INI lines are to force the From Address to be used !
mail($emailaddress, $emailsubject, $msg, $headers);
ini_restore(sendmail_from);
echo "mail send";
}
# To Email Address
$emailaddress="to@address.com";
# From Email Address
$fromaddress = "from@address.com";
# Message Subject
$emailsubject="This is a test mail with some attachments";
# Use relative paths to the attachments
$attachments = Array(
Array("file"=>"../../test.doc", "content_type"=>"application/msword"),
Array("file"=>"../../123.pdf", "content_type"=>"application/pdf")
);
# Message Body
$body="This is a message with <b>".count($attachments)."</b> attachments and maybe some <i>HTML</i>!";
send_mail($emailaddress, $fromaddress, $emailsubject, $body, $attachments);
?>
p_p at rg dot ru
13-Dec-2006 03:37
This function don`t may replace in the header in the field "envelope-from". It`s no good.
brett at brettbrewer dot com
05-Dec-2006 07:05
I was having problems with all php emails showing up on my Exchange server as attachements instead of normal emails. I discovered that Exchange needs the MIME Version header. I simply added this to the beginning of my email headers:
$headers .= "MIME-Version: 1.0\r\n";
Now messages show up properly when they arrive at my Exchange server.
d dot g dot clau at NOSPAM dot gmail dot com
12-Nov-2006 01:00
Sending mail with php can be quite tricky, especially when mail() is disabled and/or SMTP service is not available. POSS can be the solution, a mail() clone with buil-in MTA, available here: http://poss.sourceforge.net/email/ .
anselm at netuxo dot co dot uk
10-Nov-2006 10:31
In case you don't want to, or can't, configure sendmail for your server, a good alternative is esmtp - it's an smtp mailer with minimum configuration that can be used as a sendmail drop-in : http://esmtp.sourceforge.net/
furrykef at gmail dot com
03-Nov-2006 10:44
By the way, also read RFC 3696 and its errata. These define rules for e-mail addresses in more plain language.
furrykef at gmail dot com
03-Nov-2006 10:38
If you use a regexp to validate an e-mail address, be sure that you actually use a correct regexp. In particular, there are more valid punctuation characters than you may think. All of these characters may appear to the left of the at-sign: ! # $ % & ' * + - / = ? ^ _ ` { | } ~
Don't believe me? Look at RFC 2822, which defines the current standard for e-mail addresses. ;)
There's no reason, other than laziness, to reject e-mail address that contain these characters to the left of the at-sign. You might think that nobody uses these characters, but people who write incorrect regexps are one reason why. Do your part to correct this situation. :)
Note in particular the plus sign. Many regexps reject addresses with the plus sign, but there are e-mail addresses that have them. In particular, gmail has a special feature called "plus addressing", so that if your username is "joeuser", you can use "joeuser+web at gmail dot com" and "joeuser+business at gmail dot com" as separate addresses, and the e-mail will be sorted depending on which address was used.
Even allowing all those punctuation characters isn't enough to fully satisfy RFC2822. For example, you can use quoted strings to allow spaces in e-mail addresses, such as "joe user" at somewhere dot com. But I wouldn't worry about such things too much, because they're too obscure; just make sure you get all the punctuation characters in there.
krzystu at krzystu dot net
19-Oct-2006 09:41
What about Bounce parameter for sendmail:
"-f $from" as the fifth one. Without that Return-Path will be set to sendmail administrator
Super David
16-Aug-2006 01:30
Just to follow up on Nick Baicoianu's useful note below, one minor correction to make (it drove me insane for a while there until I noticed it):
This line:
<?php
$msg .= "Content-Type: multipart/alternative; boundary=\"".$htmlalt_mime_boundary."\"".$eol;
?>
Should in fact read:
<?php
$headers .= "Content-Type: multipart/alternative; boundary=\"".$htmlalt_mime_boundary."\"".$eol;
?>
The line should be declared as a header, not as part of the message content.
Nick Baicoianu
14-Aug-2006 07:19
In response to jcwebb's excellent post regarding multipart/alternative and attachments: the code works great in sending attachments, but I got inconsistent results across different email clients (MS Outlook worked, but Thunderbird and mutt didn't) when displaying the HTML/plain text alternate portion.
To fix this, you need to define a new MIME boundary for the HTML/Plain text alternates section ONLY - this way you can "nest" the two together so the alternate works properly in all email clients.
here's a modified version of the code for the message body only (see jcwebb's post for the entire message code)
<?
$msg = "";
# Attachment
$msg .= "--".$mime_boundary.$eol;
$msg .= "Content-Type: application/pdf; name=\"".$letter."\"".$eol; // sometimes i have to send MS Word, use 'msword' instead of 'pdf'
$msg .= "Content-Transfer-Encoding: base64".$eol;
$msg .= "Content-Disposition: attachment; filename=\"".$letter."\"".$eol.$eol; // !! This line needs TWO end of lines !! IMPORTANT !!
$msg .= $f_contents.$eol.$eol;
# Setup for text OR html -
$msg .= "--".$mime_boundary.$eol;
$htmlalt_mime_boundary = $mime_boundary."_htmlalt"; //we must define a different MIME boundary for this section for the alternative to work properly in all email clients
$msg .= "Content-Type: multipart/alternative; boundary=\"".$htmlalt_mime_boundary."\"".$eol;
# Text Version
$msg .= "--".$htmlalt_mime_boundary.$eol;
$msg .= "Content-Type: text/plain; charset=iso-8859-1".$eol;
$msg .= "Content-Transfer-Encoding: 8bit".$eol;
$msg .= "This is a multi-part message in MIME format.".$eol;
$msg .= "If you are reading this, please update your email-reading-software.".$eol;
$msg .= "+ + Text Only Email from Genius Jon + +".$eol.$eol;
# HTML Version
$msg .= "--".$htmlalt_mime_boundary.$eol;
$msg .= "Content-Type: text/html; charset=iso-8859-1".$eol;
$msg .= "Content-Transfer-Encoding: 8bit".$eol;
$msg .= $body.$eol.$eol;
//close the html/plain text alternate portion
$msg .= "--".$htmlalt_mime_boundary."--".$eol.$eol;
# Finished
$msg .= "--".$mime_boundary."--".$eol.$eol;
?>
expertphp at gmail dot com
12-Jul-2006 05:05
For all those having problems sending messages to INBOX (spam-free messages)
i recommend using FromHost() function from XPM2's SMTP class.
With this function you can set the name of the host that is sending the message.
Pay very much attention when using this function, because i recommend the IP address of the host
to reflect the MX zone declared for it, and the IP address of the mail sender.
A simple example of how to use for sending an e-mail directly to the client:
<?php
$hostname = 'maildomain.net';
// path to smtp.php file from XPM2 package for inclusion
require_once '/path/smtp.php';
$mail = new SMTP;
$mail->Delivery('client');
$mail->From('me@'.$hostname, 'My name');
$mail->FromHost($hostname, $havemx);
if(!$havemx) die("The hostname: '".$hostname."' doesn't have a valid MX zone!");
$mail->AddTo('client@destination.net');
$mail->Text('It is simple to use XPM2');
$sent = $mail->Send('Hello World!');
echo $sent ? 'Success.' : $mail->result;
?>
This is one of the most reliable anti-spam/bulk mail techniques.
For more details visit: http://xpertmailer.sourceforge.net/DOCUMENTATION/
chris at w3style dot co dot uk
27-May-2006 07:10
mail() opens a new connection for each email it sends out which causes some significant overhead if you're sending out many emails in one go.
You can avoid this by using sockets like Antony Male has done and then send as many emails as you like through the same connection. It should be noted however that some MTA's will reject your emails after you've sent over a certain threshold on the same connection (about 10 would be normal) so it's worth disconnecting and reconnecting periodically.
I'm surprised nobody has drawn attention to PHPMailer (http://phpmailer.sourceforge.net) which makes this sort of stuff really easy. Even better still is Swift Mailer by Chris Corbyn (http://www.swiftmailer.org) because it includes plugin support and it's tighter.
Another thing that's bitten me before is Magic Quotes! If it's turned on and you're sending attachments that seem to arrive corrupted it's more than likely because your attachments are full of backslashes.
Hope the links might be useful to some people :)
josephcmiller2 at gmail dot com
26-May-2006 02:26
I have been using the function mymail() provided by Antony Male (below) to send mail on my server, but with a couple of modifications. First, I needed to enable AUTH LOGIN in order to use my smtp server from my ISP. Second, his mymail() function allows for a $from to be used, but the function does not accept any such parameter. I have addressed the latter issue by parsing the headers to obtain the From: address. If this is not provided, failed mail will not be returned properly to the sender.
// modified to provide authenticated logins
function mymail($to,$subject,$message,$headers)
{
// set as global variable
global $GLOBAL;
// get From address
if ( preg_match("/From:.*?[A-Za-z0-9\._%-]+\@[A-Za-z0-9\._%-]+.*/", $headers, $froms) ) {
preg_match("/[A-Za-z0-9\._%-]+\@[A-Za-z0-9\._%-]+/", $froms[0], $fromarr);
$from = $fromarr[0];
}
// Open an SMTP connection
$cp = fsockopen ($GLOBAL["SMTP_SERVER"], $GLOBAL["SMTP_PORT"], &$errno, &$errstr, 1);
if (!$cp)
return "Failed to even make a connection";
$res=fgets($cp,256);
if(substr($res,0,3) != "220") return "Failed to connect";
// Say hello...
fputs($cp, "HELO ".$GLOBAL["SMTP_SERVER"]."\r\n");
$res=fgets($cp,256);
if(substr($res,0,3) != "250") return "Failed to Introduce";
// perform authentication
fputs($cp, "auth login\r\n");
$res=fgets($cp,256);
if(substr($res,0,3) != "334") return "Failed to Initiate Authentication";
fputs($cp, base64_encode($GLOBAL["SMTP_USERNAME"])."\r\n");
$res=fgets($cp,256);
if(substr($res,0,3) != "334") return "Failed to Provide Username for Authentication";
fputs($cp, base64_encode($GLOBAL["SMTP_PASSWORD"])."\r\n");
$res=fgets($cp,256);
if(substr($res,0,3) != "235") return "Failed to Authenticate";
// Mail from...
fputs($cp, "MAIL FROM: <$from>\r\n");
$res=fgets($cp,256);
if(substr($res,0,3) != "250") return "MAIL FROM failed";
// Rcpt to...
fputs($cp, "RCPT TO: <$to>\r\n");
$res=fgets($cp,256);
if(substr($res,0,3) != "250") return "RCPT TO failed";
// Data...
fputs($cp, "DATA\r\n");
$res=fgets($cp,256);
if(substr($res,0,3) != "354") return "DATA failed";
// Send To:, From:, Subject:, other headers, blank line, message, and finish
// with a period on its own line (for end of message)
fputs($cp, "To: $to\r\nFrom: $from\r\nSubject: $subject\r\n$headers\r\n\r\n$message\r\n.\r\n");
$res=fgets($cp,256);
if(substr($res,0,3) != "250") return "Message Body Failed";
// ...And time to quit...
fputs($cp,"QUIT\r\n");
$res=fgets($cp,256);
if(substr($res,0,3) != "221") return "QUIT failed";
return true;
}
martin dot felis at gmx dot de
11-Mar-2006 03:03
If using a chroot environment and you don't want to have a full mailer in it, mini-sendmail (can be found at http://www.acme.com/software/mini_sendmail/) is very useful. It is just a small binary that sends mails over your local mta over port 25.
Martin
derernst at gmx dot ch
17-Feb-2006 04:43
Suggestion for methods checking form inputs for e-mail injection attempts.
Any inputs expected from single-line text fields can just be refused if they contain a newline character. The second function tries to minimize matches on non-evil inputs by matching suspect strings only if preceded by a newline character. (Anyway, if this is considered to be safe, it will of course do it for single-line inputs, too.)
<?php
/**
* Check single-line inputs:
* Returns false if text contains newline character
*/
function has_no_newlines($text)
{
return preg_match("/(%0A|%0D|\\n+|\\r+)/i", $text) == 0;
}
/**
* Check multi-line inputs:
* Returns false if text contains newline followed by
* email-header specific string
*/
function has_no_emailheaders($text)
{
return preg_match("/(%0A|%0D|\\n+|\\r+)(content-type:|to:|cc:|bcc:)/i", $text) == 0;
}
?>
jcwebb at dicoe dot com
08-Feb-2006 10:16
Corrupted Attachments ???
I spent many hours with corrupted attachments (of all types of files) - The answer: a blank line is needed after $msg.=$file \r\n \r\n [incredible but true].
Heres some useful code for sending an attachment, and display html OR text depending on the users email-reader.
i work with many different systems, so...
<?php # Is the OS Windows or Mac or Linux
if (strtoupper(substr(PHP_OS,0,3
|