Send email using Socket
Among the several PHP homepage spaces that the author has applied for, there are really not many that can provide mail functions. After calling the mail() function, there is always nothing to do. But email plays a growing role in online life. Think about it, can an internet bug be called a real internet bug if he surfs the Internet without receiving emails? I don’t want to talk about the role of email
anymore, but what should I do if the homepage space does not support mail() sending? I also thought about sending emails
through socket, but I am not familiar with socket programming using PHP. In addition, sending emails requires the SMTP protocol and I need to read a lot of English, so
I have never studied it. Finally one day I found an article about using socket programming to send emails. I copied it as if I had found a treasure, and transformed it into a class available in PHP for everyone to use. The original article was just a simple example, and there were
some errors. After many experiments and transformations, I finally changed it into a class that directly uses sockets to send emails to specified mailboxes, such as
If you combine it with the previous article about sending MIME, you can send emails on websites that do not support the mail() function. Because the process of sending
emails takes time, it may not be exactly the same as the processing mechanism of mail(), so the speed is slower, but it can solve the urgent need to send
emails. At the same time, you can also learn Use php for socket programming. Next, I will introduce the implementation principle of this class to you,
and also explain some basic knowledge about SMTP to you.
Introduction to Socket Programming
I would like to point out to everyone that I am not a TCP/IP programming expert, so I am just sharing my understanding and experience here.
Use the fsockopen function to open an Internet connection. The function syntax format is:
int fsockopen(string hostname, int port, int [errno], string [errstr], int [timeout]);
I don’t think I need to talk about the meaning of the parameters. Since the SMTP protocol is used here, the port number is 25. After the connection is successfully opened, a
socket handle will be returned, which can be used like a file handle. Available operations include fputs(), fgets(), feof(), fclose()
, etc.
That’s it for a very simple introduction.
Basics of SMTP
The general command format of the Internet protocol based on TCP/IP is implemented through the request/response method, and all text information is used, so
it is easier to process. SMTP is the abbreviation of Simple Mail Transfer Protocol, which enables the client to send emails to the server. So
The command mentioned below refers to the client sending a request instruction to the server, and the response refers to the information returned by the server to the client.
SMTP is divided into two parts: command header and message body. The command header mainly completes the connection between the client and the server, verification, etc. The whole process consists of multiple
commands. After each command is sent to the server, the server will give response information, usually a 3-digit response code and response text. The response codes returned by different servers
comply with the protocol, but the response text does not. There is a carriage return character at the end of each command and response, so that
can use fputs() and fgets() to process commands and responses. SMTP command and response messages are single lines. The message body is the body part of the email
, and the final closing line should be a separate "." as the closing line.
Some commonly used SMTP commands on the client are:
HELO hostname: greet the server and tell the client the machine name used, you can fill it in casually
MAIL FROM: sender_id: tell the server to send The address of the recipient
RCPT TO: receiver_id: Tell the server the address of the recipient
DATA: The content of the letter will be transmitted below, and it will end with a special line containing only .
RESET: Cancel the previous command and start again Start
VERIFY userid: Verify whether the account exists (this command is optional and may not be supported by the server)
QUIT: Exit the connection, end
The response information returned by the server is (the format is: response code + Space + explanation):
220 Service ready (this information will be returned when the socket connection is successful)
221 Processing
250 The request email action is correct and completed (HELO, MAIL FROM, RCPT TO , this information will be returned if the QUIT command is executed successfully)
354 Start sending data and end with . (This information will be returned if the DATA command is executed successfully, the client should send the information)
500 Syntax error, the command cannot be recognized
550 The command cannot be executed and the mailbox is invalid
552 Interrupt processing: The user has exceeded the file space
A simple command header is given below (this is done after opening the socket). I am sending an email to stmp.263.net Test results:
HELO limodou
250 smtp.263.net
MAIL FROM: chatme@263.net
250 Ok
RCPT TO: chatme@263.net
250 Ok
DATA
354 End data with .
To: chatme@263.net
From: chatme@263.net
Subject: test
From: chatme@263. net
test
.
QUIT
250 Ok: queued as C46411C5097E0
This is some simple knowledge about SMTP. Related content can be found in RFC.
RFC 821 defines related commands for receiving/sending emails.
RFC 822 specifies the format of email content.
RFC 2045-2048 formulates the format of multimedia email content, and
RFC 1113, 1422-1424 discusses how to improve the confidentiality of email.
Implementation of send_mail class
Now I will introduce the sending mail class I wrote. With the above preparatory knowledge, the following is the implementation.
Member variables of the class
var $lastmessage; //Record the last response message returned
var $lastact; //The last action, in string form
var $welcome ; //Used behind HELO, users are welcome
var $debug; //Whether to display debugging information
var $smtp; //smtp server
var $port; //smtp port number
var $fp; //socket handle
Among them, $lastmessage and $lastact are used to record the last response information and the executed command. When an error occurs, the user can use them
. For testing needs, I also defined the $debug variable. When its value is true, some execution information will be displayed during the running process. Otherwise, there will be no
any output. $fp is used to save the opened socket handle.
Construction of classes
-------------------------------- ---------------------------------------------
function send_mail($smtp, $welcome="", $debug=false)
{
if(empty($smtp)) die("SMTP cannt be NULL!");
$this- >smtp=$smtp;
if(empty($welcome))
{
$this->welcome=gethostbyaddr("localhost");
}
else
$this->welcome=$welcome;
$this->debug=$debug;
$this->lastmessage="";
$this->lastact="";
$this->port="25";
}
-------------------------------- --------------------------------------------------
This constructor mainly completes the determination and setting of some initial values. $welcome is used in the HELO directive to tell the server the user's name.
The HELO command requires a machine name, but it can be used without it. If the user does not provide $welcome, the local machine name is automatically searched.
Show debugging information
---------------------------------- ---------------------------------------------
1 function show_debug($message, $inout)
2 {
3 if ($this->debug)
4 {
5 if($inout=="in") //Response message
6 {
7 $m='<< ';
8 }
9 else
10 $m='>> ';
11 if(!ereg ("n$", $message))
12 $message .= "
";
13 $message=nl2br($message);
14 echo "${m}${message}";
15 }
16 }
-------------------------- -------------------------------------------------- ----------
This function is used to display debugging information. You can specify in $inout whether it is an upload instruction or a returned response. If it is an upload instruction,
use "out"; if it is a returned response, use "in".
Line 3 determines whether to output debugging information.
Line 5, determine whether it is a response message. If so, add "<< " in front of the information on line 7 to distinguish the information; otherwise, add
">> on line 10 ; " to distinguish upload instructions.
Lines 11-12, determine whether the last information string is a newline character, and if not, add an HTML newline mark. Line 13 converts all newline characters into HTML
newline tags.
Line 14, output the entire message, and set the color of the message to gray to show the difference.
Execute a command
-------------------------------- ---------------------------------------------
1 function do_command($command, $code)
2 {
3 $this->lastact=$command;
4 $this->show_debug($this->lastact, "out ");
5 fputs ( $this->fp, $this->lastact );
6 $this->lastmessage = fgets ( $this->fp, 512 );
7 $this->show_debug($this->lastmessage, "in");
8 if(!ereg("^$code", $this->lastmessage))
9 {
10 return false;
11 }
12 else
13 return true;
14 }
-------------------------- -------------------------------------------------- ----------
When writing the socket processing part, I found that the processing of some commands is very similar, such as HELO, MAIL FROM, RCPT TO, QUIT, and DATA commands.
All require debugging to be displayed based on whether The information will display the relevant content. At the same time, if the returned response code is expected, the processing should continue.
If it is not expected, the processing should be interrupted. Therefore, for the sake of clarity and simplification, a general processing function is specially written for processing these commands.
$code in the parameter of the function is the expected response code. If the response code is the same, it means the processing is successful, otherwise an error occurs.
Line 3 records the last executed command.
Line 4 displays the upload command.
Line 5 uses fputs to actually transfer instructions to the server.
Line 6, the response information received from the server will be placed in the last response message variable.
Line 7 displays the response information.
Line 8 determines whether the response information is expected. If so, line 13 returns success (true), otherwise line 10 returns failure (false).
In this way, on the one hand, this function completes the function of sending and displaying instructions and information, and on the other hand, it judges whether the returned response is successful.
Email sending processing
The following is the real secret, but you have to read it carefully.:)
--------------------------------------------------------------------------------
1 function send( $to,$from,$subject,$message)
2 {
3
4 //连接服务器
5 $this->lastact="connect";
6
7 $this->show_debug("Connect to SMTP server : ".$this->smtp, "out");
8 $this->fp = fsockopen ( $this->smtp, $this->port );
9 if ( $this->fp )
10 {
11
12 set_socket_blocking( $this->fp, true );
13 $this->lastmessage=fgets($this->fp,512);
14 $this->show_debug($this->lastmessage, "in");
15
16 if (! ereg ( "^220", $this->lastmessage ) )
17 {
18 return false;
19 }
20 else
21 {
22 $this->lastact="HELO " . $this->welcome . "n";
23 if(!$this->do_command($this->lastact, "250"))
24 {
25 fclose($this->fp);
26 return false;
27 }
28
29 $this->lastact="MAIL FROM: $from" . "n";
30 if(!$this->do_command($this->lastact, "250"))
31 {
32 fclose($this->fp);
33 return false;
34 }
35
36 $this->lastact="RCPT TO: $to" . "n";
37 if(!$this->do_command($this->lastact, "250"))
38 {
39 fclose($this->fp);
40 return false;
41 }
42
43 //发送正文
44 $this->lastact="DATAn";
45 if(!$this->do_command($this->lastact, "354"))
46 {
47 fclose($this->fp);
48 return false;
49 }
50
51 //处理Subject头
52 $head="Subject: $subjectn";
53 if(!empty($subject) && !ereg($head, $message))
54 {
55 $message = $head.$message;
56 }
57
58 //处理From头
59 $head="From: $fromn";
60 if(!empty($from) && !ereg($head, $message))
61 {
62 $message = $head.$message;
63 }
64
65 //处理To头
66 $head="To: $ton";
67 if(!empty($to) && !ereg($head, $message))
68 {
69 $message = $head.$message;
70 }
71
72 //加上结束串
73 if(!ereg("n.n", $message))
74 $message .= "n.n";
75 $this->show_debug($message, "out");
76 fputs($this->fp, $message);
77
78 $this->lastact="QUITn";
79 if(!$this->do_command($this->lastact, "250"))
80 {
81 fclose($this->fp);
82 return false;
83 }
84 }
85 return true;
86 }
87 else
88 {
89 $this->show_debug("Connect failed!", "in");
90 return false;
91 }
92 }
--------------------------------------------------------------------------------
有些意思很清楚的我就不说了。
这个函数一共有四个参数,分别是$to表示收信人,$from表示发信人,$subject表求邮件主题和$message
表示邮件体。如果处理成功则返回true,失败则返回false。
第8行,连接邮件服务器,如果成功响应码应为220。
第12行,设置阻塞模式,表示信息必须返回才能继续。详细说明看手册吧。
第16行,判断响应码是否为220,如果是,则继续处理,否则出错返回。
第22-27行,处理HELO指令,期望响应码为250。
第29-34行,处理MAIL FROM指令,期望响应码为250。
第36-41行,处理RCPT TO指令,期望响应码为250。
第44-49行,处理DATA指令,期望响应码为354。
第51-76行,生成邮件体,并发送。
第52-56行,如果$subject不为空,则查找邮件体中是否有主题部分,如果没有,则加上主题部分。
第59-63行,如果$from不为空,则查找邮件体中是否有发信人部分,如果没有,则加上发信人部分。
第66-70行,如果$to不为空,则查找邮件体中是否有收信人部分,如果没有,则加上收信人部分。
第73-74行,查找邮件体是否有了结束行,如果没有则加上邮件体的结束行(以"."作为单独的一行的特殊行)。
第76行,发送邮件体。
第78-83行,执行QUIT结否与服务器的连接,期望响应码为250。
第85行,返回处理成功标志(true)。
第81-91行,与服务器连接失败的处理。
以上为整个send_mail类的实现,应该不是很难的。下面给出一个实例。
E-mail sending example
First give the simplest example:
-------------------------- -------------------------------------------------- ----
1 include "sendmail.class.php3";
2 $email="Hello, this is a test letter!";
3 $sendmail=new send_mail ("smtp.263.net", "limodou", true); //Display the modulation information
4 if($sendmail->send("chatme@263.net", "chatme@263.net" , "test", $email))
5 {
6 echo "Sent successfully!
";
7 }
8 else
9 {
10 echo " Sending failed!
";
11 }
?>
-------------------------- -------------------------------------------------- ---
Line 1, load the send_mail class.
Line 3, create an instance of the class and set the display debugging information. If you don’t want to display it, you can
$sendmail=new send_mail("smtp.263.net");.
Line 4, send email.
Pretty simple, isn’t it? Next, we will give an example of sending an HTML attachment based on the previous example of sending a MIME email.
-------------------------------------------------- ------------------------------------
include "MIME.class.php3";
//Note, in the article about sending MIME emails, the name of this class file is MIME.class. Here I changed it to something like this
$to = 'chatme @263.net'; //Changed to the recipient's email address
$str = "Newsletter for ".date('M Y', time());
//The information was changed by me
$html_data = '