[PHP] PHP laravel使用自定义邮件类实现发送邮件

2082 0
黑夜隐士 2022-11-6 08:28:59 | 显示全部楼层 |阅读模式
当登录邮箱为腾讯企业邮箱的时候。
Phpmailer发送邮件就不好用了,具体哪里不好用,我没真没找到。
但是,邮件得发啊,怎么办呢?
我这里搞了一个自定义的发送邮件类,腾讯企业邮箱也可用。
但是,邮件发送失败,不会返回报错信息,这个可能是有点坑。
源码如下:
  1. <?php
  2. namespaceApp\Extend;
  3. useException;
  4. /**
  5. *一个简单的PHPSMTP发送邮件类
  6. */
  7. classSmtpMail
  8. {
  9. /**
  10. *@varstring邮件传输代理用户名
  11. *@accessprivate
  12. */
  13. private$_userName;
  14. /**
  15. *@varstring邮件传输代理密码
  16. *@accessprivate
  17. */
  18. private$_password;
  19. /**
  20. *@varstring邮件传输代理服务器地址
  21. *@accessprivate
  22. */
  23. private$_sendServer;
  24. /**
  25. *@varint邮件传输代理服务器端口
  26. *@accessprivate
  27. */
  28. private$_port;
  29. /**
  30. *@varstring发件人
  31. *@accessprotected
  32. */
  33. protected$_from;
  34. /**
  35. *@varstring收件人
  36. *@accessprotected
  37. */
  38. protected$_to;
  39. /**
  40. *@varstring抄送
  41. *@accessprotected
  42. */
  43. protected$_cc;
  44. /**
  45. *@varstring秘密抄送
  46. *@accessprotected
  47. */
  48. protected$_bcc;
  49. /**
  50. *@varstring主题
  51. *@accessprotected
  52. */
  53. protected$_subject;
  54. /**
  55. *@varstring邮件正文
  56. *@accessprotected
  57. */
  58. protected$_body;
  59. /**
  60. *@varstring附件
  61. *@accessprotected
  62. */
  63. protected$_attachment;
  64. /**
  65. *@varreourcesocket资源
  66. *@accessprotected
  67. */
  68. protected$_socket;
  69. /**
  70. *@varreource是否是安全连接
  71. *@accessprotected
  72. */
  73. protected$_isSecurity;
  74. /**
  75. *@varstring错误信息
  76. *@accessprotected
  77. */
  78. protected$_errorMessage;
  79. protected$_debug=false;
  80. /*输出调试信息*/
  81. privatefunctiondebug($msg)
  82. {
  83. if($this->_debug){
  84. echo$msg,'<br>',"\n";
  85. }
  86. }
  87. publicfunctionsetDebug($val=true)
  88. {
  89. $this->_debug=$val;
  90. }
  91. /**
  92. *设置邮件传输代理,如果是可以匿名发送有邮件的服务器,只需传递代理服务器地址就行
  93. *@accesspublic
  94. *@paramstring$server代理服务器的ip或者域名
  95. *@paramstring$username认证账号
  96. *@paramstring$password认证密码
  97. *@paramint$port代理服务器的端口,smtp默认25号端口
  98. *@paramboolean$isSecurity到服务器的连接是否为安全连接,默认false
  99. *@returnboolean
  100. */
  101. publicfunctionsetServer($server,$username="",$password="",$port=25,$isSecurity=false)
  102. {
  103. $this->_sendServer=$server;
  104. $this->_port=$port;
  105. $this->_isSecurity=$isSecurity;
  106. $this->_userName=empty($username)?"":base64_encode($username);
  107. $this->_password=empty($password)?"":base64_encode($password);
  108. returntrue;
  109. }
  110. /**
  111. *设置发件人
  112. *@accesspublic
  113. *@paramstring$from发件人地址
  114. *@returnboolean
  115. */
  116. publicfunctionsetFrom($from)
  117. {
  118. $this->_from=$from;
  119. returntrue;
  120. }
  121. /**
  122. *设置收件人,多个收件人,调用多次.
  123. *@accesspublic
  124. *@paramstring$to收件人地址
  125. *@returnboolean
  126. */
  127. publicfunctionsetReceiver($to)
  128. {
  129. if(isset($this->_to)){
  130. if(is_string($this->_to)){
  131. $this->_to=array($this->_to);
  132. $this->_to[]=$to;
  133. returntrue;
  134. }elseif(is_array($this->_to)){
  135. $this->_to[]=$to;
  136. returntrue;
  137. }else{
  138. returnfalse;
  139. }
  140. }else{
  141. $this->_to=$to;
  142. returntrue;
  143. }
  144. }
  145. /**
  146. *设置抄送,多个抄送,调用多次.
  147. *@accesspublic
  148. *@paramstring$cc抄送地址
  149. *@returnboolean
  150. */
  151. publicfunctionsetCc($cc)
  152. {
  153. if(isset($this->_cc)){
  154. if(is_string($this->_cc)){
  155. $this->_cc=array($this->_cc);
  156. $this->_cc[]=$cc;
  157. returntrue;
  158. }elseif(is_array($this->_cc)){
  159. $this->_cc[]=$cc;
  160. returntrue;
  161. }else{
  162. returnfalse;
  163. }
  164. }else{
  165. $this->_cc=$cc;
  166. returntrue;
  167. }
  168. }
  169. /**
  170. *设置秘密抄送,多个秘密抄送,调用多次
  171. *@accesspublic
  172. *@paramstring$bcc秘密抄送地址
  173. *@returnboolean
  174. */
  175. publicfunctionsetBcc($bcc)
  176. {
  177. if(isset($this->_bcc)){
  178. if(is_string($this->_bcc)){
  179. $this->_bcc=array($this->_bcc);
  180. $this->_bcc[]=$bcc;
  181. returntrue;
  182. }elseif(is_array($this->_bcc)){
  183. $this->_bcc[]=$bcc;
  184. returntrue;
  185. }else{
  186. returnfalse;
  187. }
  188. }else{
  189. $this->_bcc=$bcc;
  190. returntrue;
  191. }
  192. }
  193. /**
  194. *设置邮件附件,多个附件,调用多次
  195. *@accesspublic
  196. *@paramstring$file文件地址
  197. *@returnboolean
  198. */
  199. publicfunctionaddAttachment($file)
  200. {
  201. if(!file_exists($file)){
  202. $this->_errorMessage="file".$file."doesnotexist.";
  203. returnfalse;
  204. }
  205. if(isset($this->_attachment)){
  206. if(is_string($this->_attachment)){
  207. $this->_attachment=array($this->_attachment);
  208. $this->_attachment[]=$file;
  209. returntrue;
  210. }elseif(is_array($this->_attachment)){
  211. $this->_attachment[]=$file;
  212. returntrue;
  213. }else{
  214. returnfalse;
  215. }
  216. }else{
  217. $this->_attachment=$file;
  218. returntrue;
  219. }
  220. }
  221. /**
  222. *设置邮件信息
  223. *@accesspublic
  224. *@paramstring$body邮件主题
  225. *@paramstring$subject邮件主体内容,可以是纯文本,也可是是HTML文本
  226. *@returnboolean
  227. */
  228. publicfunctionsetMail($subject,$body)
  229. {
  230. $this->_subject=$subject;
  231. $this->_body=base64_encode($body);
  232. returntrue;
  233. }
  234. /**
  235. *发送邮件
  236. *@accesspublic
  237. *@returnboolean
  238. */
  239. publicfunctionsend()
  240. {
  241. $command=$this->getCommand();
  242. $this->_isSecurity?$this->socketSecurity():$this->socket();
  243. foreach($commandas$value){
  244. $result=$this->_isSecurity?$this->sendCommandSecurity($value[0],$value[1]):$this->sendCommand($value[0],$value[1]);
  245. if($result){
  246. continue;
  247. }else{
  248. returnfalse;
  249. }
  250. }
  251. //其实这里也没必要关闭,smtp命令:QUIT发出之后,服务器就关闭了连接,本地的socket资源会自动释放
  252. $this->_isSecurity?$this->closeSecutity():$this->close();
  253. returntrue;
  254. }
  255. /**
  256. *返回错误信息
  257. *@returnstring
  258. */
  259. publicfunctionerror()
  260. {
  261. if(!isset($this->_errorMessage)){
  262. $this->_errorMessage="";
  263. }
  264. return$this->_errorMessage;
  265. }
  266. /**
  267. *返回mail命令
  268. *@accessprotected
  269. *@returnarray
  270. */
  271. protectedfunctiongetCommand()
  272. {
  273. $separator="----=_Part_".md5($this->_from.time()).uniqid();//分隔符
  274. $command=array(
  275. array("HELOsendmail\r\n",250)
  276. );
  277. if(!empty($this->_userName)){
  278. $command[]=array("AUTHLOGIN\r\n",334);
  279. $command[]=array($this->_userName."\r\n",334);
  280. $command[]=array($this->_password."\r\n",235);
  281. }
  282. //设置发件人
  283. $command[]=array("MAILFROM:<".$this->_from.">\r\n",250);
  284. $header="FROM:<".$this->_from.">\r\n";
  285. //设置收件人
  286. if(is_array($this->_to)){
  287. $count=count($this->_to);
  288. for($i=0;$i<$count;$i++){
  289. $command[]=array("RCPTTO:<".$this->_to[$i].">\r\n",250);
  290. if($i==0){
  291. $header.="TO:<".$this->_to[$i].">";
  292. }elseif($i+1==$count){
  293. $header.=",<".$this->_to[$i].">\r\n";
  294. }else{
  295. $header.=",<".$this->_to[$i].">";
  296. }
  297. }
  298. }else{
  299. $command[]=array("RCPTTO:<".$this->_to.">\r\n",250);
  300. $header.="TO:<".$this->_to.">\r\n";
  301. }
  302. //设置抄送
  303. if(isset($this->_cc)){
  304. if(is_array($this->_cc)){
  305. $count=count($this->_cc);
  306. for($i=0;$i<$count;$i++){
  307. $command[]=array("RCPTTO:<".$this->_cc[$i].">\r\n",250);
  308. if($i==0){
  309. $header.="CC:<".$this->_cc[$i].">";
  310. }elseif($i+1==$count){
  311. $header.=",<".$this->_cc[$i].">\r\n";
  312. }else{
  313. $header.=",<".$this->_cc[$i].">";
  314. }
  315. }
  316. }else{
  317. $command[]=array("RCPTTO:<".$this->_cc.">\r\n",250);
  318. $header.="CC:<".$this->_cc.">\r\n";
  319. }
  320. }
  321. //设置秘密抄送
  322. if(isset($this->_bcc)){
  323. if(is_array($this->_bcc)){
  324. $count=count($this->_bcc);
  325. for($i=0;$i<$count;$i++){
  326. $command[]=array("RCPTTO:<".$this->_bcc[$i].">\r\n",250);
  327. if($i==0){
  328. $header.="BCC:<".$this->_bcc[$i].">";
  329. }elseif($i+1==$count){
  330. $header.=",<".$this->_bcc[$i].">\r\n";
  331. }else{
  332. $header.=",<".$this->_bcc[$i].">";
  333. }
  334. }
  335. }else{
  336. $command[]=array("RCPTTO:<".$this->_bcc.">\r\n",250);
  337. $header.="BCC:<".$this->_bcc.">\r\n";
  338. }
  339. }
  340. //主题
  341. $header.="Subject:".$this->_subject."\r\n";
  342. if(isset($this->_attachment)){
  343. //含有附件的邮件头需要声明成这个
  344. $header.="Content-Type:multipart/mixed;\r\n";
  345. }elseif(false){
  346. //邮件体含有图片资源的需要声明成这个
  347. $header.="Content-Type:multipart/related;\r\n";
  348. }else{
  349. //html或者纯文本的邮件声明成这个
  350. $header.="Content-Type:multipart/alternative;\r\n";
  351. }
  352. //邮件头分隔符
  353. $header.="\t".'boundary="'.$separator.'"';
  354. $header.="\r\nMIME-Version:1.0\r\n";
  355. $header.="\r\n--".$separator."\r\n";
  356. $header.="Content-Type:text/html;charset=utf-8\r\n";
  357. $header.="Content-Transfer-Encoding:base64\r\n\r\n";
  358. $header.=$this->_body."\r\n";
  359. $header.="--".$separator."\r\n";
  360. //加入附件
  361. if(isset($this->_attachment)&&!empty($this->_attachment)){
  362. if(is_array($this->_attachment)){
  363. $count=count($this->_attachment);
  364. for($i=0;$i<$count;$i++){
  365. $header.="\r\n--".$separator."\r\n";
  366. $header.="Content-Type:".$this->getMIMEType($this->_attachment[$i]).';name="'.basename($this->_attachment[$i]).'"'."\r\n";
  367. $header.="Content-Transfer-Encoding:base64\r\n";
  368. $header.='Content-Disposition:attachment;filename="'.basename($this->_attachment[$i]).'"'."\r\n";
  369. $header.="\r\n";
  370. $header.=$this->readFile($this->_attachment[$i]);
  371. $header.="\r\n--".$separator."\r\n";
  372. }
  373. }else{
  374. $header.="\r\n--".$separator."\r\n";
  375. $header.="Content-Type:".$this->getMIMEType($this->_attachment).';name="'.basename($this->_attachment).'"'."\r\n";
  376. $header.="Content-Transfer-Encoding:base64\r\n";
  377. $header.='Content-Disposition:attachment;filename="'.basename($this->_attachment).'"'."\r\n";
  378. $header.="\r\n";
  379. $header.=$this->readFile($this->_attachment);
  380. $header.="\r\n--".$separator."\r\n";
  381. }
  382. }
  383. //结束邮件数据发送
  384. $header.="\r\n.\r\n";
  385. $command[]=array("DATA\r\n",354);
  386. $command[]=array($header,250);
  387. $command[]=array("QUIT\r\n",221);
  388. return$command;
  389. }
  390. /**
  391. *发送命令
  392. *@accessprotected
  393. *@paramstring$command发送到服务器的smtp命令
  394. *@paramint$code期望服务器返回的响应吗
  395. *@returnboolean
  396. */
  397. protectedfunctionsendCommand($command,$code)
  398. {
  399. //debug('Sendcommand:'.$command.',expectedcode:'.$code);
  400. //发送命令给服务器
  401. try{
  402. if(socket_write($this->_socket,$command,strlen($command))){
  403. //当邮件内容分多次发送时,没有$code,服务器没有返回
  404. if(empty($code)){
  405. returntrue;
  406. }
  407. //读取服务器返回
  408. $data=trim(socket_read($this->_socket,1024));
  409. //debug('response:'.$data);
  410. if($data){
  411. $pattern="/^".$code."/";
  412. if(preg_match($pattern,$data)){
  413. returntrue;
  414. }else{
  415. $this->_errorMessage="Error:".$data."|**|command:";
  416. returnfalse;
  417. }
  418. }else{
  419. $this->_errorMessage="Error:".socket_strerror(socket_last_error());
  420. returnfalse;
  421. }
  422. }else{
  423. $this->_errorMessage="Error:".socket_strerror(socket_last_error());
  424. returnfalse;
  425. }
  426. }catch(Exception$e){
  427. $this->_errorMessage="Error:".$e->getMessage();
  428. }
  429. }
  430. /**
  431. *发送命令
  432. *@accessprotected
  433. *@paramstring$command发送到服务器的smtp命令
  434. *@paramint$code期望服务器返回的响应吗
  435. *@returnboolean
  436. */
  437. protectedfunctionsendCommandSecurity($command,$code)
  438. {
  439. //debug('Sendcommand:'.$command.',expectedcode:'.$code);
  440. try{
  441. if(fwrite($this->_socket,$command)){
  442. //当邮件内容分多次发送时,没有$code,服务器没有返回
  443. if(empty($code)){
  444. returntrue;
  445. }
  446. //读取服务器返回
  447. $data=trim(fread($this->_socket,1024));
  448. //debug('response:'.$data);
  449. if($data){
  450. $pattern="/^".$code."/";
  451. if(preg_match($pattern,$data)){
  452. returntrue;
  453. }else{
  454. $this->_errorMessage="Error:".$data."|**|command:";
  455. returnfalse;
  456. }
  457. }else{
  458. returnfalse;
  459. }
  460. }else{
  461. $this->_errorMessage="Error:".$command."sendfailed";
  462. returnfalse;
  463. }
  464. }catch(Exception$e){
  465. $this->_errorMessage="Error:".$e->getMessage();
  466. }
  467. }
  468. /**
  469. *读取附件文件内容,返回base64编码后的文件内容
  470. *@accessprotected
  471. *@paramstring$file文件
  472. *@returnmixed
  473. */
  474. protectedfunctionreadFile($file)
  475. {
  476. if(file_exists($file)){
  477. $file_obj=file_get_contents($file);
  478. returnbase64_encode($file_obj);
  479. }else{
  480. $this->_errorMessage="file".$file."dosenotexist";
  481. returnfalse;
  482. }
  483. }
  484. /**
  485. *获取附件MIME类型
  486. *@accessprotected
  487. *@paramstring$file文件
  488. *@returnmixed
  489. */
  490. protectedfunctiongetMIMEType($file)
  491. {
  492. if(file_exists($file)){
  493. $mime=mime_content_type($file);
  494. if(!preg_match("/gif|jpg|png|jpeg/",$mime)){
  495. $mime="application/octet-stream";
  496. }
  497. return$mime;
  498. }else{
  499. returnfalse;
  500. }
  501. }
  502. /**
  503. *建立到服务器的网络连接
  504. *@accessprivate
  505. *@returnboolean
  506. */
  507. privatefunctionsocket()
  508. {
  509. //创建socket资源
  510. $this->_socket=socket_create(AF_INET,SOCK_STREAM,getprotobyname('tcp'));
  511. if(!$this->_socket){
  512. $this->_errorMessage=socket_strerror(socket_last_error());
  513. returnfalse;
  514. }
  515. socket_set_block($this->_socket);//设置阻塞模式
  516. //连接服务器
  517. if(!socket_connect($this->_socket,$this->_sendServer,$this->_port)){
  518. $this->_errorMessage=socket_strerror(socket_last_error());
  519. returnfalse;
  520. }
  521. $str=socket_read($this->_socket,1024);
  522. if(!strpos($str,"220")){
  523. $this->_errorMessage=$str;
  524. returnfalse;
  525. }
  526. returntrue;
  527. }
  528. /**
  529. *建立到服务器的SSL网络连接
  530. *@accessprivate
  531. *@returnboolean
  532. */
  533. privatefunctionsocketSecurity()
  534. {
  535. $remoteAddr="tcp://".$this->_sendServer.":".$this->_port;
  536. $this->_socket=stream_socket_client($remoteAddr,$errno,$errstr,30);
  537. if(!$this->_socket){
  538. $this->_errorMessage=$errstr;
  539. returnfalse;
  540. }
  541. //设置加密连接,默认是ssl,如果需要tls连接,可以查看php手册stream_socket_enable_crypto函数的解释
  542. stream_socket_enable_crypto($this->_socket,true,STREAM_CRYPTO_METHOD_SSLv23_CLIENT);
  543. stream_set_blocking($this->_socket,1);//设置阻塞模式
  544. $str=fread($this->_socket,1024);
  545. if(!strpos($str,"220")){
  546. $this->_errorMessage=$str;
  547. returnfalse;
  548. }
  549. returntrue;
  550. }
  551. /**
  552. *关闭socket
  553. *@accessprivate
  554. *@returnboolean
  555. */
  556. privatefunctionclose()
  557. {
  558. if(isset($this->_socket)&&is_object($this->_socket)){
  559. $this->_socket->close();
  560. returntrue;
  561. }
  562. $this->_errorMessage="Noresourcecantobeclose";
  563. returnfalse;
  564. }
  565. /**
  566. *关闭安全socket
  567. *@accessprivate
  568. *@returnboolean
  569. */
  570. privatefunctioncloseSecutity()
  571. {
  572. if(isset($this->_socket)&&is_object($this->_socket)){
  573. stream_socket_shutdown($this->_socket,STREAM_SHUT_WR);
  574. returntrue;
  575. }
  576. $this->_errorMessage="Noresourcecantobeclose";
  577. returnfalse;
  578. }
  579. }
复制代码
关于laravel5.8框架如何引入第三方类库,请参考下文补充内容 laravel8大同小异。
调用方法:
  1. /**
  2. *@name:发送邮件方法
  3. *@author:camellia
  4. *@date:2021-01-19
  5. *@param:$emailstring发送给谁
  6. *@param:$mail_titlestring邮件标题
  7. *@param:$mail_bodystring邮件内容
  8. *@return:$resultbooltrue/false
  9. */
  10. publicfunctionsend_mail($email,$mail_title,$mail_body)
  11. {
  12. $mail=newSmtpMail();
  13. $mail->setServer(EMAIL_SERVER,SEND_EMAIL,EMAIL_SECERT,465,true);//参数1(qq邮箱使用smtp.qq.com,qq企业邮箱使用smtp.exmail.qq.com),参数2(邮箱登陆账号),参数3(邮箱登陆密码,也有可能是独立密码,就是开启pop3/smtp时的授权码),参数4(默认25,腾云服务器屏蔽25端口,所以用的465),参数5(是否开启ssl,用465就得开启)//$mail->setServer("XXXXX","joffe@XXXXX","XXXXX",465,true);
  14. $mail->setFrom(SEND_EMAIL,"时间里的博客");//发送者邮箱
  15. $mail->setReceiver($email);//接收者邮箱
  16. $mail->addAttachment("");//Attachment附件,不用可注释
  17. $mail->setMail($mail_title,$mail_body);//标题和内容
  18. $result=$mail->send();//可以var_dump一下,发送成功会返回true,失败false
  19. return$result;//*/
  20. }
复制代码
代码亲测可用。
补充
laravel5.8引入第三方类库的方法详解
有需求需要使用PHPMailer发送邮件。
那么首先需要引入PHPMailer这个第三方的类库。我是这样做的:
1:在app目录下新建Extend目录。如下图所示:


将PHPMailer放入Extend目录下。如下图所示


2:修改项目根目录下的composer.json文件
  1. "autoload": {
  2.         "psr-4": {
  3.             "App\": "app/"
  4.         },
  5.         "classmap": [
  6.             "database/seeds",
  7.             "database/factories",
  8.             "app/Extend/PHPMailer/src"
  9.         ]
  10.     },
复制代码
添加你第三方类库的位置到autoload中
3:执行composer命令,在网站根目录下:
composer dump-autoload
4:调用:
(1):使用命名空间
  1. use PHPMailer\src\PHPMailer;
复制代码
(2):调用
  1. //实例化PHPMailer核心类
  2. $mail = new PHPMailer();
复制代码
如果报错,就在实例化前边加一个转义符\
至此,laravel引入第三方类库成功。
以上就是PHP laravel使用自定义邮件类实现发送邮件的详细内容,更多关于PHP laravel发送邮件的资料请关注中国红客联盟其它相关文章!

本帖子中包含更多资源

您需要 登录 才可以下载或查看,没有账号?立即注册

×
您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

中国红客联盟公众号

联系站长QQ:5520533

admin@chnhonker.com
Copyright © 2001-2025 Discuz Team. Powered by Discuz! X3.5 ( 粤ICP备13060014号 )|天天打卡 本站已运行