【PHP基础知识】——操作Email

2023-11-03

邮件已经成为我们生活中不可或缺的信息沟通方式,时常需要我们去群发或者定时发送一下邮件给指定对象,例如系统的故障报警邮件,批量回复一些服务信息等。因此,将发送邮件功能做到后台可配置或者自动化是程序开发的重要部分。像Java等语言一样,下面我们也来罗列一下PHP操作Email的发送和接收功能。

一、邮件服务协议

1、简单邮件传输协议(SMTP) 是一个相对简单的基于文本的协议。在其之上指定了一条消息的一个或多个接收者(在大多数情况下被确认是存在的),然后消息文本会被传输。可以很简单地通过telnet程序来测试一个SMTP服务器。SMTP默认使用TCP端口25。

2、POP3协议:负责从邮件服务器中检索电子邮件。它要求邮件服务器完成下面几种任务之一:从邮件服务器中检索邮件并从服务器中删除这个邮件;从邮件服务器中检索邮件但不删除它;不检索邮件,只是询问是否有新邮件到达。POP协议支持传输任何格式的文件,包括图片和声音文件等。在用户阅读邮件时,POP命令所有的邮件信息立即下载到用户的计算机上,不在服务器上保留

3、IMAP协议:互联网信息访问协议(IMAP)是一种优于POP的新协议。和POP一样,IMAP也能下载邮件、从服务器中删除邮件或询问是否有新邮件,但IMAP克服了POP的一些缺点。例如,它可以决定客户机请求邮件服务器提交所收到邮件的方式,请求邮件服务器只下载所选中的邮件而不是全部邮件。客户机可先阅读邮件信息的标题和发送者的名字再决定是否下载这个邮件。通过用户的客户机电子邮件程序,IMAP可让用户在服务器上创建并管理邮件文件夹或邮箱、删除邮件、查询某封信的一部分或全部内容,完成所有这些工作时都不需要把邮件从服务器下载到用户的个人计算机上。

二、终端命令行操作邮件服务器的方式

1、通过tls方式连接邮件服务器和发送邮件:telnet <域名> <端口>
通过以上命令即可访问到邮件服务器,并请求连接,具体连接过程示例如下:
①telnet <域名> 25
返回220 Anti-spam GT for Coremail System 

②helo localhost    //helo 向服务器发出标志自己身份的命令
返回250 OK 

③auth login        //用于请求认证和连接邮件服务器
返回334 dXNlcm5hbWU6 //后面那一串是base64encode后的字符串,解码后是username

④输入base64编码后的用户名
返回334 UGFzc3dvcmQ6 //后面那一串是base64encode后的字符串,解码后是password

⑤输入base64编码后的密码
返回235 Authentication successful        //连接成功

⑥mail
 from:<yourmailaddress>        //注释邮件发送者
返回250 Mail OK

⑦rcpt
 to:<dstmailaddress>            //注释邮件接收者
返回250 Mail OK

⑧data                    //data命令开始书写邮件内容
to:dstmailaddress        //收件人邮箱跟上文保持一致
from:yourmailaddress    //发件人邮箱跟上文保持一致
subject:test
mail
//空一行
This is a test mail….
//空一行
.                    //注释:<点>+<回车> 正文内容结束标志
返回250 Mail OK queued as smtp12,EMCowABnovABxQ1XZjKTAQ--.7259S2 1460520311

⑨退出:quit

2、通过ssl方式连接和操作邮件服务器发送邮件:
openssl s_client -connect servername:端口号(默认465)
第②步开始和tls连接方式一致。

ssl和tls方式的差别:
SSL是Netscape开发的专门用户保护Web通讯的,目前版本为3.0。最新版本的TLS 1.0是IETF(工程任务组)制定的一种新的协议,它建立在SSL 3.0协议规范之上,是SSL 3.0的后续版本。两者差别极小,可以理解为SSL 3.1,它是写入了RFC的。 

流程图(引用)如下:


两者的端口如下:


三、PHP操作请求邮件服务器

1、使用tls发送邮件:

class SMTP {

	var $connection;
	var $recipients;
	var $headers;
	var $timeout;
	var $errors;
	var $status;
	var $body;
	var $from;
	var $host;
	var $port;
	var $helo;
	var $auth;
	var $user;
	var $pass;

	/**
	 *  参数为一个数组
	 *  host        SMTP 服务器的主机       默认:localhost
	 *  port        SMTP 服务器的端口       默认:25
	 *  helo        发送HELO命令的名称      默认:localhost
	 *  user        SMTP 服务器的用户名     默认:空值
	 *  pass        SMTP 服务器的登陆密码   默认:空值
	 *  timeout     连接超时的时间          默认:5
	 * @return  bool
	 */
	function SMTP($params = array()) {

		if (!defined('CRLF')) {
			define('CRLF', "\r\n", true);
		}

		$this->timeout = 10;
		$this->status = 1;
		$this->host = 'localhost';
		$this->port = 25;
		$this->auth = false;
		$this->user = '';
		$this->pass = '';
		$this->errors = array();

		foreach ($params AS $key => $value) {
			$this->$key = $value;
		}

		$this->helo = $this->host;

		//  如果没有设置用户名则不验证
		$this->auth = ('' == $this->user) ? false : true;

	}

	function connect($params = array()) {

		if (!isset($this->status)) {
			$obj = new SMTP($params);

			if ($obj->connect()) {
				$obj->status = 2;
			}

			return $obj;
		} else {
			$this->connection = @fsockopen($this->host, $this->port, $errno, $errstr, $this->timeout);
			@socket_set_timeout($this->connection, 0, 250000);

			$greeting = $this->get_data();
			if (is_resource($this->connection)) {
				$this->status = 2;
				return $this->auth ? $this->ehlo() : $this->helo();
			} else {
				$this->errors[] = 'Failed to connect to server: ' . $errstr;
				return false;
			}
		}
	}

	/**
	 * 参数为数组
	 * recipients      接收人的数组
	 * from            发件人的地址,也将作为回复地址
	 * headers         头部信息的数组
	 * body            邮件的主体
	 */

	function send($params = array()) {

		foreach ($params AS $key => $value) {
			$this->set($key, $value);
		}

		if ($this->is_connected()) {
			//  服务器是否需要验证
			if ($this->auth) {
				if (!$this->auth()) {
					return false;
				}
			}

			$this->mail($this->from);

			if (is_array($this->recipients)) {
				foreach ($this->recipients AS $value) {
					$this->rcpt($value);
				}
			} else {
				$this->rcpt($this->recipients);
			}

			if (!$this->data()) {
				return false;
			}

			$headers = str_replace(CRLF . '.', CRLF . '..', trim(implode(CRLF, $this->headers)));
			$body = str_replace(CRLF . '.', CRLF . '..', $this->body);
			$body = $body[0] == '.' ? '.' . $body : $body;

			$this->send_data($headers);
			$this->send_data('');
			$this->send_data($body);
			$this->send_data('.');

			return (substr($this->get_data(), 0, 3) === '250');

		} else {
			$this->errors[] = 'Not connected!';
			return false;
		}
	}

	function helo() {
		if (is_resource($this->connection)
			AND $this->send_data('HELO ' . $this->helo)
				AND substr($error = $this->get_data(), 0, 3) === '250'
		) {
			return true;
		} else {
			$this->errors[] = 'HELO command failed, output: ' . trim(substr($error, 3));
			return false;
		}
	}

	function ehlo() {
		if (is_resource($this->connection)
			AND $this->send_data('EHLO ' . $this->helo)
				AND substr($error = $this->get_data(), 0, 3) === '250'
		) {
			return true;
		} else {
			$this->errors[] = 'EHLO command failed, output: ' . trim(substr($error, 3));
			return false;
		}
	}

	function auth() {
		if (is_resource($this->connection)
			AND $this->send_data('AUTH LOGIN')
				AND substr($error = $this->get_data(), 0, 3) === '334'
					AND $this->send_data(base64_encode($this->user)) // Send username
						AND substr($error = $this->get_data(), 0, 3) === '334'
							AND $this->send_data(base64_encode($this->pass)) // Send password
								AND substr($error = $this->get_data(), 0, 3) === '235'
		) {
			return true;
		} else {
			$this->errors[] = 'AUTH command failed: ' . trim(substr($error, 3));
			return false;
		}
	}

	function mail($from) {
		if ($this->is_connected()
			AND $this->send_data('MAIL FROM:<' . $from . '>')
				AND substr($this->get_data(), 0, 2) === '250'
		) {
			return true;
		} else {
			return false;
		}
	}

	function rcpt($to) {
		if ($this->is_connected()
			AND $this->send_data('RCPT TO:<' . $to . '>')
				AND substr($error = $this->get_data(), 0, 2) === '25'
		) {
			return true;
		} else {
			$this->errors[] = trim(substr($error, 3));
			return false;
		}
	}

	function data() {
		if ($this->is_connected()
			AND $this->send_data('DATA')
				AND substr($error = $this->get_data(), 0, 3) === '354'
		) {
			return true;
		} else {
			$this->errors[] = trim(substr($error, 3));
			return false;
		}
	}

	function is_connected() {
		return (is_resource($this->connection) && ($this->status === 2));
	}

	function send_data($data) {
		if (is_resource($this->connection)) {
			return fwrite($this->connection, $data . CRLF, strlen($data) + 2);
		} else {
			return false;
		}
	}

	function get_data() {
		$return = '';
		$line = '';

		if (is_resource($this->connection)) {
			while (strpos($return, CRLF) === false OR $line{3} !== ' ') {
				$line = fgets($this->connection, 512);
				$return .= $line;
			}

			return trim($return);
		} else {
			return '';
		}
	}

	function set($var, $value) {
		$this->$var = $value;
		return true;
	}

	/**
	 * 获得最后一个错误信息
	 *
	 * @access  public
	 * @return  string
	 */
	function error_msg() {
		if (!empty($this->errors)) {
			$len = count($this->errors) - 1;
			return $this->errors[$len];
		} else {
			return '';
		}
	}

}


2、使用ssl发送邮件:
和tls一致,只需要在@fsockopen()方法的host参数前面加上'ssl://'的字符串即可,当然端口要改为465。

3、接收邮件

邮件接收可分为POP3和IMAP协议两种,具体方法可参照:https://my.oschina.net/idufei/blog/40150


4、附上SMTP类的调用方法:

//将邮件参数配置写在$GLOBALS['MAIL_CONFIG']数组里,在框架入口引入即可。
class Mailer {

	private $smtpHost;
	private $smtpPort;
	private $smtpSSL;
	private $smptAuthUser;
	private $smtpAuthPassword;
	private $fromName;
	private $fromEmail;

	public function __construct($config = null) {

		$config = $config ? $config : $GLOBALS['MAIL_CONFIG'];
		$this->smtpHost = $config['SMTP_HOST'];
		$this->smtpPort = $config['SMTP_PORT'];
		$this->smptAuthUser = $config['SMTP_AUTH_USER'];
		$this->smtpAuthPassword = $config['SMTP_AUTH_PASSWORD'];
		$this->fromName = $config['FROM_NAME'];
		$this->fromEmail = $config['FROM_EMAIL'];

	}

	/**
	 * 发送邮件
	 * @param  $toName 收件人名称
	 * @param  $toEmail 收件人邮箱
	 * @param  $subject 主题
	 * @param  $content 内容
	 * @param int $contentType 信件内容类型 0-text/plain 1-text/html
	 * @param string $fromName 发信人名称
	 * @param string $fromEmail 发信人邮箱
	 * @return bool
	 */
	public function sendMail($toName, $toEmail, $subject, $content, $contentType = 0, $fromName = '', $fromEmail = '') {

		$charset = 'utf-8';

		if (!$fromName) $fromName = $this->fromName;
		if (!$fromEmail) $fromEmail = $this->fromEmail;

		/* 邮件的头部信息 */
		$content_type = ($contentType == 0) ? 'Content-Type: text/plain; charset=' . $charset : 'Content-Type: text/html; charset=' . $charset;
		$content = base64_encode($content);

		$headers[] = 'Date: ' . gmdate('D, j M Y H:i:s') . ' +0000';
		$headers[] = 'To: "' . '=?' . $charset . '?B?' . base64_encode($toName) . '?=' . '" <' . $toEmail . '>';
		$headers[] = 'From: "' . '=?' . $charset . '?B?' . base64_encode($fromName) . '?=' . '" <' . $fromEmail . '>';
		$headers[] = 'Subject: ' . '=?' . $charset . '?B?' . base64_encode($subject) . '?=';
		$headers[] = $content_type . '; format=flowed';
		$headers[] = 'Content-Transfer-Encoding: base64';
		$headers[] = 'Content-Disposition: inline';

		/* 获得邮件服务器的参数设置 */
		$params['host'] = $this->smtpHost;
		$params['port'] = $this->smtpPort;
		$params['user'] = $this->smptAuthUser;
		$params['pass'] = $this->smtpAuthPassword;

		if (empty($params['host']) || empty($params['port'])) {
			die("No SMTP Host!");
		} else {

			// 发送邮件
			static $smtp;

			$send_params['recipients'] = $toEmail;
			$send_params['headers'] = $headers;
			$send_params['from'] = $fromEmail;
			$send_params['body'] = $content;

			if (!isset($smtp)) {
				$smtp = new SMTP($params);
			}

			if ($smtp->connect() && $smtp->send($send_params)) {
				return true;
			} else {
				echo $smtp->error_msg();
				return false;
			}
		}

	}

}


本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

【PHP基础知识】——操作Email 的相关文章

  • 使用“INSERT ... ON DUPLICATE KEY UPDATE”插入多条记录

    我的表结构 table marks 我的目标 我想用条件插入或更新多条记录 我目前正在通过此查询进行检查 第一步 SELECT FROM marks WHERE student 115 AND param 1 第二步 if records
  • MySQL 和 PHP 参数 1 作为资源

    好吧 当我运行下面提到的代码时 PHP 向我抛出此错误 在日志中 Error mysql num rows 期望参数 1 为资源 第 10 行 place 中给出的字符串 9 11号线 queryFP SELECT FROM db coun
  • 如何仅删除页面的自动段落格式,而不删除帖子的自动段落格式(WordPress)

    我已经熟悉这个在 WordPress 中删除自动段落格式的小技巧 remove filter the content wpautop remove filter the excerpt wpautop 但是添加这个函数 php删除整个网站的
  • xdebug.remote_handler 在 PHP.INI 中设置,但未在 PHPinfo 中显示

    我正在尝试让 Xbdebug 与 NetBeans 一起运行 以便调试一些 PHP 代码 我确信几年前我已经让它工作了 然后切换了 IDE 现在想切换回来 When I try to debug the status bar shows 并
  • 在laravel中组合两个不同的无关系数据库表查询进行分页

    我的数据库中有两个不相关的表 我需要将它们合并 以便我可以将其放在我的搜索视图中 但我不知道是否可能 这是我的代码 这news and season表不相关 但它们具有相似的列 我试图将其放入一个对象中以便于分页 是否可以 search r
  • 解析错误:语法错误,意外的 T_RETURN [关闭]

    这个问题不太可能对任何未来的访客有帮助 它只与一个较小的地理区域 一个特定的时间点或一个非常狭窄的情况相关 通常不适用于全世界的互联网受众 为了帮助使这个问题更广泛地适用 访问帮助中心 help reopen questions 遇到这个问
  • 收到警告“标头不能包含多个标头,检测到新行”

    我正在用 oops 进行编码 以便用 PHP 上传图像 但是提交图片后却出现警告 标题不能包含多个标题 检测到新行 下面是我的函数 它给出了错误 public function ft redirect query if REQUEST UR
  • Laravel - 急切加载 Eloquent 模型的方法(而不是关系)

    就像我们可以急切加载 Eloquent 模型的关系一样 有没有办法急切加载不是 Eloquent 模型的关系方法的方法 例如 我有一个 Eloquent 模型GradeReport它有以下方法 public function totalSc
  • 如何从脚本中创建新的 Joomla 用户帐户?

    我们正在为 Joomla 创建一个 XML API 允许合作伙伴网站在我们的网站上为其用户创建新帐户 我们已经创建了一个独立的 PHP 脚本来处理和验证 API 请求 但现在我们需要实际创建新帐户 我们最初只想进行 CURL 调用来提交注册
  • 将IP保存到数据库中

    当用户登录时 我想将他们的 IP 保存在数据库中 我该怎么做呢 MySQL 字段最适合使用哪种类型 获取IP的PHP代码是什么样的 我正在考虑将其用作登录 会话内容的额外安全功能 我正在考虑使用用户现在拥有的 IP 检查用户从数据库登录的
  • yii2 中的自动完成

    在 Yii2 中 我希望当用户开始输入时 我的输入字段之一能够自动完成 下面是我的代码 它使用Jui Autocomplete 这是行不通的 当我打印我的数组时 我就像 Array 1 gt abc 2 gt xyz 4 gt pqr
  • 如何使用 jQuery Ajax 将 PHP 数组值传递到另一个文件?

    这是我的代码
  • 使用 :hover 作为元素的内联样式(使用 HTML/CSS/php)[重复]

    这个问题在这里已经有答案了 可能的重复 如何将 a hover 规则嵌入到文档中间的样式属性中 https stackoverflow com questions 131653 how do i embed an ahover rule i
  • 使用 yum 和 pear 安装 php-soap 均失败

    我正在尝试在 Centos 6 4 服务器上安装 PHP 的 SOAP 扩展 我对包管理器 从 CLI 安装包并在 PHP 中配置它们相当不熟悉 我相当有能力管理 php ini 和其他 PHP 配置文件 soap ini 等 我尝试使用以
  • PHP LDAP 查询获取特定安全组的成员

    我正在努力让 LDAP 查询工作来为我提供安全组的成员 我们的活动目录结构设置为 DC domain DC co dc uk然后 我们有一个名为 公司用户 的 OU 其中有一个用于 IT 和标准的 OU 在这些中我们创建了用户 所以我被设置
  • 设置大型电子邮件通知系统有哪些方法?

    我的公司有一个用 PHP 构建的网站 我们使用内置的 PHP 电子邮件功能每天向订阅者发送数千封电子邮件 这是一个糟糕的主意 它堵塞了我们的服务器 并且需要几个小时才能完成整个批次 现在我已经研究过像 MailChimp 这样的群发邮件服务
  • PHP 中的encodeURI() ?

    PHP 中是否有一些不编码的encodeURI 函数 我现在用这个 function encodeURI url http php net manual en function rawurlencode php https develope
  • 使用 PHP 中的 GD 库在图像上绘图

    我创建了一个代码来生成随机图案图像 它创建一个具有给定宽度和高度的图像 并用 40x40 像素的小矩形填充它 这是我的代码
  • 使用 MYSQL 将 h:mm pm/am 时间格式插入数据库

    我正在尝试将以 h mm am pm 格式写入的时间插入到存储为标准 DATETIME 格式 hh mm ss 的数据库中 但我不知道如何将发布的时间转换为标准格式所以数据库会接受它 这是我到目前为止一直在尝试的 title POST in
  • Readfile 从大文件中读取 0 字节?

    我正在尝试通过以下方式发送一个大文件readfile 但是 没有任何内容发送到浏览器 并且readfile 回报0 not false 我尝试发送的文件大小为 4GiB 并且可由 PHP 读取 我正在设置set time limit 0 以

随机推荐

  • 前端常用代码

    ajax请求demo KaTeX parse error Expected got EOF at end of input son url ctx camera capture getListJson action capture came
  • lightGBM专题2:基于pyspark在spark平台下lightgbm训练详解

    数据集 这里以数据集flight weather csv为例 文件下载地址 flight weather csv 将flight weather csv上传到hdfs 这里上传到目录 home 必须在hdfs下读取指定目录的文件 数据读取
  • 服务器虚拟多主机,服务器虚拟多台主机

    服务器虚拟多台主机 内容精选 换一换 主机迁移服务是一种P2V V2V迁移服务 可以帮您把X86物理服务器或者私有云 公有云平台上的虚拟机迁移到华为云弹性云服务器上 从而帮助您轻松地把服务器上的应用和数据迁移到华为云 特点 界面化操作 简单
  • linux命令整理

    pwd 在两个不同目录下使用此命令 ls 长格式 短格式 多个短格式组合使用 cd 上一级目录 下一级目录 相对路径使用 绝对路径使用 特殊符号使用 less more 注意找区别 less的作用与more十分相似 不同点为less命令允许
  • linux下生成静态库.a与动态库.o的方法流程

    比如我们随便从github下载一个zlib的开源库 作者都是告诉了我们这个库的使用方法 并写好了MakeLists txt了 所以直接 先建立一个build文件夹 用来存放生成的编译文件 gt 接着cmake gt 再make 编译后得到了
  • vmware VSAN 双节点部署

    一 环境 ESxi主机 01 192 168 2 26 ESxi主机 02 192 168 2 27 见证主机 虚拟机 192 168 2 157 部署在ESxi 主机01上 注 此操作官方不推荐 192 168 2 26虚拟交换机配置如下
  • Python中default()函数

    阅读textual inversion代码的时候 遇到这样一个用法 def p losses self x start t noise None noise default noise lambda torch randn like x s
  • 【python】运行/调用/执行/终止/重启.exe文件

    一 运行 调用 执行 打开 exe文件 1 os system cmd command 使用 import os os system cmd command 括号里输入的参数即为在cmd里面输入的内容 具体格式参照这个连接 python中o
  • UE5实现距离测量功能

    文章目录 1 实现目标 2 实现过程 2 1 Widget 2 2 蓝图实现 3 参考资料 1 实现目标 UE5在Runtime环境下测量两个空间点位之间的绝对距离 并支持多段线的距离测量 GIF动图如下所示 2 实现过程 实现原理比较简单
  • Django新增自定义模板函数

    Django新增自定义模板函数 1 创建templatetags文件 2 创建一个 py文件 coding utf 8 from django import template register名称不可改 register template
  • 【数据结构与算法】3、虚拟头节点、动态数组的缩容、动态数组和单链表的复杂度、数组的随机访问

    目录 一 虚拟头节点 二 数组的随机访问 三 动态数组 链表复杂度分析 四 动态数组 add E element 复杂度分析 五 动态数组的缩容 一 虚拟头节点 为了让代码更加精简 统一所有节点的处理逻辑 可以在最前面增加一个虚拟的头节点
  • mybatis-plus设置主键自增 ,获取自增主键id

    第一步 实体类加注解 在主键上加 TableId type IdType AUTO 注解 第二步 在数据库设置主键自增 第二种 可以在mapper插入标签中添加keyProperty id useGeneratedKeys true
  • Courses

    点击打开链接 Problem Description Consider a group of N students and P courses Each student visits zero one or more than one co
  • 网络编程-----socket函数

    1 Socket 函数 访问底层操作系统接口的全部方法 提供服务中心类 简化网络服务器的开发 语法 socket socket family type proto family 套接字家族可以是 AF UNIX 或者 AF INET typ
  • Vue.js 2 渐进式前端框架 的最佳学习方法

    Vue js作为一个后起的前端框架 借鉴了Angular React等现代前端框架 库的诸多特点 并且 取得了相当不错的成绩 Vue js的定位是一个渐进式框架 作者的说法是 与其他框架的区别就是渐进式的想法 也就是Progressive
  • 转:Python2字符编码问题汇总

    这篇文章的部分问题在Python3以后不再存在 老猿只是觉得文章的部分内容还是有参考价值 因此在此原文转发连接 Python2字符编码问题汇总
  • 第三章——Lyapunov理论基础

    文章目录 3 1 非线性系统和平衡点 非线性系统 自治与非自治系统 平衡点 常规运动 3 2 稳定性的概念 稳定性与非稳定性 渐进稳定性和指数稳定性 局部和全局稳定性 3 3 线性化和局部稳定性 3 4 Lyapunov直接法 正定函数和L
  • python的高级变量类型

    1 Python 中数据类型可以分为 数字型 和 非数字型 数字型 整型 int 浮点型 float 布尔型 bool 真 True 非 0 数 非零即真 假 False 0 复数型 complex 主要用于科学计算 例如 平面场问题 波动
  • (C语言)关于浮点数和0比较大小

    对于浮点数a 不能用if a 0 来判断a与0的大小 应该判断a是否位于0附近的一个很小的区间 EPS EPS 中 或者说a的绝对值小于等于一个很小的数EPS 可定义EPS 1e 6 即用if fabs a lt EPS 正确的实数与0的比
  • 【PHP基础知识】——操作Email

    邮件已经成为我们生活中不可或缺的信息沟通方式 时常需要我们去群发或者定时发送一下邮件给指定对象 例如系统的故障报警邮件 批量回复一些服务信息等 因此 将发送邮件功能做到后台可配置或者自动化是程序开发的重要部分 像Java等语言一样 下面我们