Email.php 14 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362
  1. <?php
  2. /*
  3. * FecShop file.
  4. *
  5. * @link http://www.fecshop.com/
  6. * @copyright Copyright (c) 2016 FecShop Software LLC
  7. * @license http://www.fecshop.com/license/
  8. */
  9. namespace fecshop\services;
  10. use Yii;
  11. /**
  12. * service mail :邮件服务部分
  13. * @author Terry Zhao <2358269014@qq.com>
  14. * @since 1.0
  15. */
  16. class Email extends Service
  17. {
  18. public $mailerConfig;
  19. // public $defaultForm;
  20. public $mailerInfo;
  21. /**
  22. * 邮件模板部分动态数据提供类的返回数据的函数名字,使用默认值即可。
  23. */
  24. public $defaultObMethod = 'getLastData';
  25. protected $_mailer; // Array
  26. protected $_mailer_from; //Array
  27. protected $_from;
  28. public function init()
  29. {
  30. parent::init();
  31. $this->mailerInfo['storeName'] = Yii::$app->store->get('email', 'baseStoreName');
  32. $this->mailerInfo['phone'] = Yii::$app->store->get('email', 'baseContactsPhone');
  33. $this->mailerInfo['contacts']['emailAddress'] = Yii::$app->store->get('email', 'baseContactsEmail');
  34. $this->mailerConfig['default']['class'] = 'yii\swiftmailer\Mailer';
  35. $this->mailerConfig['default']['transport'] = [
  36. 'class' => 'Swift_SmtpTransport',
  37. 'host' => Yii::$app->store->get('email', 'default_smtp_host'), //SMTP Host
  38. 'username' => Yii::$app->store->get('email', 'default_smtp_username'), //SMTP 账号
  39. 'password' => Yii::$app->store->get('email', 'default_smtp_password'), //SMTP 密码
  40. 'port' => Yii::$app->store->get('email', 'default_smtp_port'), //SMTP 端口
  41. 'encryption' => Yii::$app->store->get('email', 'default_smtp_encryption'),
  42. ];
  43. $this->mailerConfig['default']['messageConfig'] = ['charset'=>'UTF-8'];
  44. }
  45. /**
  46. * 在邮箱中显示的 邮箱地址
  47. */
  48. public function contactsEmailAddress()
  49. {
  50. $mailerInfo = $this->mailerInfo;
  51. if (isset($mailerInfo['contacts']['emailAddress'])) {
  52. return $mailerInfo['contacts']['emailAddress'];
  53. }
  54. }
  55. /**
  56. * 在邮箱中显示的 商城名字(Store Name).
  57. */
  58. public function storeName()
  59. {
  60. $mailerInfo = $this->mailerInfo;
  61. if (isset($mailerInfo['storeName'])) {
  62. return $mailerInfo['storeName'];
  63. }
  64. }
  65. /**
  66. * 在邮件中显示的 联系手机号
  67. * Yii::$service->email->customer->contactsPhone();.
  68. */
  69. public function contactsPhone()
  70. {
  71. $mailerInfo = $this->mailerInfo;
  72. if (isset($mailerInfo['phone'])) {
  73. return $mailerInfo['phone'];
  74. }
  75. }
  76. /**
  77. * @param $key | String
  78. * 得到MailConfig.
  79. */
  80. protected function getMailerConfig($key = 'default')
  81. {
  82. if (isset($this->mailerConfig[$key]) && $this->mailerConfig[$key]) {
  83. if (is_array($this->mailerConfig[$key])) {
  84. return $this->mailerConfig[$key];
  85. } elseif (is_string($this->mailerConfig[$key])) {
  86. return $this->getMailerConfig($this->mailerConfig[$key]);
  87. }
  88. }
  89. return '';
  90. }
  91. /**
  92. * 默认的默认form。邮件from.
  93. */
  94. protected function defaultForm($mailerConfig)
  95. {
  96. if (isset($mailerConfig['transport']['username'])) {
  97. if (!empty($mailerConfig['transport']['username'])) {
  98. return $mailerConfig['transport']['username'];
  99. }
  100. }
  101. return '';
  102. }
  103. /**
  104. * @param $mailerConfig | Array or String mailer组件的配置, 您可以设置为空,使用默认的邮箱配置,也可以设置为字符串,字符串对应配置中$mailerConfig对应的key。
  105. * 1.打开@fecshop/config/services/Config.php , 可以看到 $mailerConfig => ['default' => [...]]的配置,当该参数为空或'default'的时候,就使用该默认配置。
  106. * 2.当该参数设置除default之外的字符串的时候,就是 $mailerConfig 配置数组中其他的key对应的配置,如果不存在,则返回为空。
  107. * 3.您可以完全不使用配置数组中的配置,完全动态配置他,下面该参数动态配置的例子:
  108. * 注意:如果自定义传递邮箱配置,不同的配置,要使用不同的configKey
  109. * [
  110. * 'configKey' => [ # 唯一key,这个必须在 @fecshop/config/services/Config.php 中 $mailerConfig 配置数组中不存在该key值,否则将会重复。
  111. * 'class' => 'yii\swiftmailer\Mailer', # email组件对应的class
  112. * 'transport' => [ # 组件注入的配置参数。
  113. * 'class' => 'Swift_SmtpTransport',
  114. * 'host' => 'smtp.qq.net',
  115. * 'username' => 'support@mail.com',
  116. * 'password' => 'xxxx',
  117. * 'port' => '587',
  118. * 'encryption' => 'tls',
  119. * ],
  120. * 'messageConfig'=>[
  121. * 'charset'=>'UTF-8',
  122. * ],
  123. * ] //数组中只能一个configKey,配置多个无效,只有第一个有效。
  124. * ]
  125. * @return yii的mail组件compoent
  126. * 通过 $mailerConfigParam 的三种方式,可以使用系统配置的mail组件,也可以自己动态配置mail组件
  127. * 增强mail组件使用的方面和灵活。
  128. */
  129. protected function actionMailer($mailerConfigParam = '')
  130. {
  131. if (!$mailerConfigParam) {
  132. $key = 'default';
  133. } elseif (is_array($mailerConfigParam)) {
  134. $key_arr = array_keys($mailerConfigParam);
  135. $key = $key_arr[0];
  136. } elseif (is_string($mailerConfigParam)) {
  137. $key = $mailerConfigParam;
  138. } else {
  139. Yii::$service->helper->errors->add('you mail config param is not correct');
  140. return;
  141. }
  142. if (!$key) {
  143. Yii::$service->helper->errors->add('mail config key is empty');
  144. return;
  145. }
  146. if (!$this->_mailer[$key]) {
  147. $component_name = 'mailer_'.$key;
  148. if (!$mailerConfigParam) {
  149. $mailerConfig = $this->getMailerConfig();
  150. if (!is_array($mailerConfig) || empty($mailerConfig)) {
  151. Yii::$service->helper->errors->add('you must config mail var $mailerConfig is your mail config file');
  152. return;
  153. }
  154. Yii::$app->set($component_name, $mailerConfig);
  155. } elseif (is_array($mailerConfigParam)) {
  156. $mailerConfig = $mailerConfigParam[$key];
  157. if (!is_array($mailerConfig) || empty($mailerConfig)) {
  158. Yii::$service->helper->errors->add('function param $mailerConfigParam format is not correct');
  159. return;
  160. }
  161. $component_name .= 'custom_';
  162. Yii::$app->set($component_name, $mailerConfig);
  163. } elseif (is_string($mailerConfigParam)) {
  164. $mailerConfig = $this->getMailerConfig($mailerConfigParam);
  165. if (!is_array($mailerConfig) || empty($mailerConfig)) {
  166. Yii::$service->helper->errors->add('string param ($mailerConfigParam) can not find in config file , you must config var $mailerConfig in mail config file');
  167. return;
  168. }
  169. Yii::$app->set($component_name, $mailerConfig);
  170. }
  171. $this->_mailer_from[$key] = $this->defaultForm($mailerConfig);
  172. $this->_mailer[$key] = Yii::$app->get($component_name);
  173. }
  174. $this->_from = isset($this->_mailer_from[$key]) ? $this->_mailer_from[$key] : '';
  175. return isset($this->_mailer[$key]) ? $this->_mailer[$key] : '' ;
  176. }
  177. /**
  178. * @param $sendInfo | Array , example:
  179. * [
  180. * 'to' => $to,
  181. * 'subject' => $subject,
  182. * 'htmlBody' => $htmlBody,
  183. * 'senderName'=> $senderName,
  184. * ]
  185. * @param $mailerConfigParam | array or String,对于该参数的配置,
  186. * 您可以参看上面的函数 function actionMailer($mailerConfigParam = '') 或者到 @fecshop/config/services/Email.php参看 $mailerConfig的配置
  187. * 该函数用于发送邮件.
  188. */
  189. protected function actionSend($sendInfo, $mailerConfigParam = '')
  190. {
  191. $to = isset($sendInfo['to']) ? $sendInfo['to'] : '';
  192. $subject = isset($sendInfo['subject']) ? $sendInfo['subject'] : '';
  193. $htmlBody = isset($sendInfo['htmlBody']) ? $sendInfo['htmlBody'] : '';
  194. $senderName = isset($sendInfo['senderName']) ? $sendInfo['senderName'] : '';
  195. if (!$subject) {
  196. Yii::$service->helper->errors->add('email title is empty');
  197. return false;
  198. }
  199. if (!$htmlBody) {
  200. Yii::$service->helper->errors->add('email body is empty');
  201. return false;
  202. }
  203. $mailer = $this->mailer($mailerConfigParam);
  204. if (!$mailer) {
  205. Yii::$service->helper->errors->add('compose is empty, you must check you email config');
  206. return false;
  207. }
  208. if (!$this->_from) {
  209. Yii::$service->helper->errors->add('email send from is empty');
  210. return false;
  211. } else {
  212. $from = $this->_from;
  213. }
  214. if ($senderName) {
  215. $setFrom = [$from => $senderName];
  216. } else {
  217. $setFrom = $from;
  218. }
  219. try {
  220. $mailer->compose()
  221. ->setFrom($setFrom)
  222. ->setTo($to)
  223. ->setSubject($subject)
  224. ->setHtmlBody($htmlBody)
  225. ->send();
  226. return true;
  227. } catch (\Swift_TransportException $e) {
  228. $errorMessage = $e->getMessage();
  229. Yii::$service->helper->errors->add($errorMessage);
  230. return false;
  231. } catch (\Exception $e) {
  232. Yii::$service->helper->errors->add('send email fail');
  233. return false;
  234. }
  235. }
  236. /**
  237. * @param $widget | String,邮件模板中的动态数据的提供部分的class
  238. * @param $viewPath | String,邮件模板中的显示数据的html部分。
  239. * @param $langCode 当前的语言
  240. * @proeprty $params 传递给 $widget 对应的class,用于将数据传递过去。
  241. * 根据提供的动态数据提供者$widget 和 view路径$viewPath,语言$langCode,以及其他参数$params(这个数组会设置到$widget对应的class的params变量中)
  242. * 最终得到邮件标题和邮件内容
  243. * 如果当前语言的邮件模板不存在,则使用默认语言的模板。
  244. * 关于函数参数的例子值,可以参看配置文件 @fecshop/config/services/Email.php
  245. * 打开这个配置文件,可以看到 emailTheme部分的配置, 里面有 widget 和 viewPath的配置,
  246. * 配置和下面的参数是对应起来的,在执行下面的函数,会使用配置里面的参数,譬如:
  247. * @fecshop/services/email/Customer.php 中的函数 sendRegisterEmail($emailInfo) 里面对该函数的调用。
  248. */
  249. public function getSubjectAndBody($widget, $viewPath, $langCode = '', $params = [])
  250. {
  251. if (!$langCode) {
  252. $langCode = Yii::$service->store->currentLangCode;
  253. }
  254. if (!$langCode) {
  255. Yii::$service->helper->errors->add('langCode is empty');
  256. return;
  257. }
  258. $defaultLangCode = Yii::$service->fecshoplang->defaultLangCode;
  259. // 得到body部分的配置数组
  260. $bodyViewFile = $viewPath.'/body_'.$langCode.'.php';
  261. $bodyViewFilePath = Yii::getAlias($bodyViewFile);
  262. if (!file_exists($bodyViewFilePath)) { //如果当前语言的模板不存在,则使用默认语言的模板。
  263. $bodyViewFile = $viewPath.'/body_'.$defaultLangCode.'.php';
  264. $bodyViewFilePath = Yii::getAlias($bodyViewFile);
  265. }
  266. $bodyConfig = [
  267. 'class' => $widget,
  268. 'view' => $bodyViewFilePath,
  269. ];
  270. if (!empty($params)) {
  271. $bodyConfig['params'] = $params;
  272. }
  273. // 得到subject部分的配置数组
  274. $subjectViewFile = $viewPath.'/subject_'.$langCode.'.php';
  275. $subjectViewFilePath = Yii::getAlias($subjectViewFile);
  276. if (!file_exists($subjectViewFilePath)) {
  277. $subjectViewFile = $viewPath.'/subject_'.$defaultLangCode.'.php';
  278. $subjectViewFilePath = Yii::getAlias($subjectViewFile);
  279. }
  280. $subjectConfig = [
  281. 'class' => $widget,
  282. 'view' => $subjectViewFilePath,
  283. ];
  284. if (!empty($params)) {
  285. $subjectConfig['params'] = $params;
  286. }
  287. $emailSubject = $this->getHtmlContent($subjectConfig);
  288. $emailBody = $this->getHtmlContent($bodyConfig);
  289. return [$emailSubject, $emailBody];
  290. //$emailSubject = Yii::$service->page->widget->render($subjectConfigKey,$parentThis);
  291. //$emailBody = Yii::$service->page->widget->render($bodyConfigKey,$parentThis);
  292. }
  293. /**
  294. * @param $config | Array,example:
  295. * [
  296. * 'class' => $widget,
  297. * 'view' => $subjectViewFile,
  298. * 'params'=> $params
  299. * ];
  300. * @return String(text)
  301. * 通过配置得到邮件内容,原理是使用了 Yii::$app->view->renderFile()函数。
  302. */
  303. public function getHtmlContent($config)
  304. {
  305. if (isset($config['view']) && !empty($config['view'])) {
  306. $viewFile = $config['view'];
  307. unset($config['view']);
  308. $method = $this->defaultObMethod;
  309. $ob = Yii::createObject($config);
  310. $params = $ob->$method();
  311. return Yii::$app->view->renderFile($viewFile, $params);
  312. } else {
  313. //errors
  314. }
  315. }
  316. /**
  317. * @param $email_address | String 邮箱地址字符串
  318. * @return bool 如果格式正确,返回true
  319. */
  320. protected function actionValidateFormat($email_address)
  321. {
  322. if (preg_match("^[_a-z0-9-]+(\.[_a-z0-9-]+)*@[a-z0-9-]+(\.[a-z0-9-]+)*(\.[a-z]{2,3})$^", $email_address)) {
  323. return true;
  324. } else {
  325. return false;
  326. }
  327. }
  328. }