Mail.php 9.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257
  1. <?php
  2. /**
  3. * 邮件
  4. *
  5. * @author mybsdc <[email protected]>
  6. * @date 2019/5/12
  7. * @time 16:38
  8. */
  9. namespace Luolongfei\Libs\MessageServices;
  10. use Luolongfei\App\Exceptions\LlfException;
  11. use Luolongfei\Libs\Log;
  12. use PHPMailer\PHPMailer\PHPMailer;
  13. use PHPMailer\PHPMailer\Exception as MailException;
  14. use Luolongfei\Libs\Connector\MessageGateway;
  15. class Mail extends MessageGateway
  16. {
  17. /**
  18. * @var PHPMailer
  19. */
  20. private $phpMailerInstance;
  21. /**
  22. * @throws MailException
  23. */
  24. public function __construct()
  25. {
  26. $this->language = config('custom_language', 'zh');
  27. $this->noticeTemplatePath = sprintf('%s/mail/%s/notice.html', RESOURCES_PATH, $this->language);
  28. $this->successfulRenewalTemplatePath = sprintf('%s/mail/%s/successful_renewal.html', RESOURCES_PATH, $this->language);
  29. $this->noRenewalRequiredTemplatePath = sprintf('%s/mail/%s/no_renewal_required.html', RESOURCES_PATH, $this->language);
  30. $this->phpMailerInstance = new PHPMailer(true);
  31. $this->init();
  32. }
  33. /**
  34. * 初始化邮箱配置
  35. *
  36. * @throws MailException
  37. */
  38. protected function init()
  39. {
  40. $username = config('message.mail.username');
  41. $password = config('message.mail.password');
  42. list($host, $secure, $port) = $this->getBasicMailConf($username);
  43. $this->phpMailerInstance->SMTPDebug = config('debug') ? 2 : 0; // Debug 0:关闭 1:客户端信息 2:客户端和服务端信息
  44. $this->phpMailerInstance->isSMTP(); // 告诉 PHPMailer 使用 SMTP
  45. $this->phpMailerInstance->Host = $host; // SMTP 服务器
  46. $this->phpMailerInstance->SMTPAuth = true; // 启用 SMTP 身份验证
  47. $this->phpMailerInstance->Username = $username; // 账号
  48. $this->phpMailerInstance->Password = $password; // 密码或授权码
  49. $this->phpMailerInstance->SMTPSecure = $secure; // 将加密系统设置为使用 - ssl(不建议使用)或 tls
  50. $this->phpMailerInstance->Port = $port; // 设置 SMTP 端口号 - tsl 使用 587 端口,ssl 使用 465 端口
  51. $this->phpMailerInstance->CharSet = 'UTF-8'; // 防止中文邮件乱码
  52. $this->phpMailerInstance->setLanguage('zh_cn', VENDOR_PATH . '/phpmailer/phpmailer/language/'); // 设置语言
  53. $this->phpMailerInstance->setFrom($username, 'Im robot'); // 发件人
  54. }
  55. /**
  56. * 获取邮箱基本配置
  57. *
  58. * @param string $username
  59. *
  60. * @return array
  61. * @throws MailException
  62. */
  63. public function getBasicMailConf(string $username)
  64. {
  65. if (stripos($username, '@gmail.com') !== false) {
  66. $host = 'smtp.gmail.com';
  67. $secure = 'tls';
  68. $port = 587;
  69. } else if (stripos($username, '@qq.com') !== false) {
  70. $host = 'smtp.qq.com';
  71. $secure = 'tls';
  72. $port = 587;
  73. } else if (stripos($username, '@163.com') !== false) {
  74. $host = 'smtp.163.com';
  75. $secure = 'ssl';
  76. $port = 465;
  77. } else if (stripos($username, '@vip.163.com') !== false) {
  78. $host = 'smtp.vip.163.com';
  79. $secure = 'ssl';
  80. $port = 465;
  81. } else if (stripos($username, '@outlook.com') !== false) {
  82. $host = 'smtp.office365.com';
  83. $secure = 'starttls';
  84. $port = 587;
  85. } else {
  86. $host = config('message.mail.host');
  87. $secure = config('message.mail.encryption');
  88. $port = (int)config('message.mail.port');
  89. if (!($host && $secure && $port)) {
  90. throw new MailException(lang('100069'));
  91. }
  92. }
  93. return [$host, $secure, $port];
  94. }
  95. /**
  96. * 生成域名 html
  97. *
  98. * @param array $domains
  99. *
  100. * @return string
  101. */
  102. public function genDomainsHtml(array $domains)
  103. {
  104. $domainsHtml = '';
  105. foreach ($domains as $domain) {
  106. $domainsHtml .= sprintf('<a href="http://%s" rel="noopener" target="_blank">%s</a>', $domain, $domain);
  107. }
  108. return $domainsHtml;
  109. }
  110. /**
  111. * 生成域名状态 html
  112. *
  113. * @param array $domainStatus
  114. *
  115. * @return string
  116. */
  117. public function genDomainStatusHtml(array $domainStatus)
  118. {
  119. if (empty($domainStatus)) {
  120. return lang('100070');
  121. }
  122. $domainStatusHtml = '';
  123. foreach ($domainStatus as $domain => $daysLeft) {
  124. $domainStatusHtml .= sprintf(lang('100071'), $domain, $domain, $daysLeft);
  125. }
  126. $domainStatusHtml = rtrim(rtrim($domainStatusHtml, ' '), ',,') . lang('100072');
  127. return $domainStatusHtml;
  128. }
  129. /**
  130. * 送信
  131. *
  132. * @param string $content
  133. * @param string $subject
  134. * @param integer $type
  135. * @param array $data
  136. * @param string|null $recipient
  137. * @param mixed ...$params
  138. *
  139. * @return bool
  140. * @throws LlfException
  141. * @throws MailException
  142. */
  143. public function send(string $content, string $subject = '', int $type = 1, array $data = [], ?string $recipient = null, ...$params)
  144. {
  145. $recipient = $recipient ?: config('message.mail.to');
  146. if (!$recipient) {
  147. throw new LlfException(34520012);
  148. }
  149. $this->check($content, $data);
  150. $this->phpMailerInstance->addAddress($recipient, config('message.mail.recipient_name', lang('100073'))); // 添加收件人,参数2选填
  151. $this->phpMailerInstance->addReplyTo(config('message.mail.reply_to', '[email protected]'), config('message.mail.reply_to_name', lang('100074'))); // 备用回复地址,收到的回复的邮件将被发到此地址
  152. /**
  153. * 抄送和密送都是添加收件人,抄送方式下,被抄送者知道除被密送者外的所有的收件人,密送方式下,
  154. * 被密送者知道所有的被抄送者,但不知道其它的被密送者。
  155. * 抄送好比@,密送好比私信。
  156. */
  157. // $this->phpMailerInstance->addCC('[email protected]'); // 抄送
  158. // $this->phpMailerInstance->addBCC('[email protected]'); // 密送
  159. // 添加附件,参数2选填
  160. // $this->phpMailerInstance->addAttachment('README.md', '说明.txt');
  161. // 标题
  162. $subject = $subject === '' ? mb_substr($content, 0, 12) . '...' : $subject;
  163. $this->phpMailerInstance->Subject = $subject;
  164. // 页脚
  165. $footer = '';
  166. /**
  167. * 正文
  168. * 使用 html 文件内容作为正文,其中的图片将被 base64 编码,另确保 html 样式为内联形式,且某些样式可能需要 !important 方能正常显示,
  169. * msgHTML 方法的第二个参数指定 html 内容中图片的路径,在转换时会拼接 html 中图片的相对路径得到完整的路径,最右侧无需“/”,PHPMailer
  170. * 源码里有加。 css 中的背景图片不会被转换,这是 PHPMailer 已知问题,建议外链
  171. * 此处也可替换为:
  172. * $this->phpMailerInstance->isHTML(true); // 设为html格式
  173. * $this->phpMailerInstance->Body = '正文'; // 支持html
  174. * $this->phpMailerInstance->AltBody = 'This is an HTML-only message. To view it, activate HTML in your email application.'; // 纯文本消息正文。不支持html预览的邮件客户端将显示此预览消息,其它情况将显示正常的body
  175. */
  176. if ($type === 1) {
  177. $template = file_get_contents($this->noticeTemplatePath);
  178. $this->setCommonFooter($footer, '<br>', false);
  179. $message = $this->genMessageContent([
  180. $content,
  181. $footer
  182. ], $template);
  183. } else if ($type === 2) {
  184. $template = file_get_contents($this->successfulRenewalTemplatePath);
  185. $this->setCommonFooter($footer, '<br>', false);
  186. $realData = [
  187. $data['username'],
  188. $data['renewalSuccessArr'] ? sprintf(lang('100075'), $this->genDomainsHtml($data['renewalSuccessArr'])) : '',
  189. $data['renewalFailuresArr'] ? sprintf(lang('100076'), $this->genDomainsHtml($data['renewalFailuresArr'])) : '',
  190. $this->genDomainStatusHtml($data['domainStatusArr']),
  191. $footer
  192. ];
  193. $message = $this->genMessageContent($realData, $template);
  194. } else if ($type === 3) {
  195. $template = file_get_contents($this->noRenewalRequiredTemplatePath);
  196. $this->setCommonFooter($footer, '<br>');
  197. $realData = [
  198. $data['username'],
  199. $this->genDomainStatusHtml($data['domainStatusArr']),
  200. $footer
  201. ];
  202. $message = $this->genMessageContent($realData, $template);
  203. } else if ($type === 4) {
  204. $template = file_get_contents($this->noticeTemplatePath);
  205. $this->setCommonFooter($footer, '<br>', false);
  206. $message = $this->genMessageContent([
  207. $this->newLine2Br($content),
  208. $footer
  209. ], $template);
  210. } else {
  211. throw new \Exception(lang('100003'));
  212. }
  213. $this->phpMailerInstance->msgHTML($message, RESOURCES_PATH . '/mail/' . $this->language);
  214. try {
  215. if (!$this->phpMailerInstance->send()) {
  216. throw new MailException($this->phpMailerInstance->ErrorInfo);
  217. }
  218. return true;
  219. } catch (\Exception $e) {
  220. system_log(lang('100077') . $e->getMessage());
  221. return false;
  222. }
  223. }
  224. }