551 lines
15KB

  1. <?php
  2. /**
  3. * @link http://www.yiiframework.com/
  4. * @copyright Copyright (c) 2008 Yii Software LLC
  5. * @license http://www.yiiframework.com/license/
  6. */
  7. namespace yii\swiftmailer;
  8. use Yii;
  9. use yii\base\InvalidConfigException;
  10. use yii\helpers\ArrayHelper;
  11. use yii\mail\BaseMessage;
  12. /**
  13. * Message implements a message class based on SwiftMailer.
  14. *
  15. * @see http://swiftmailer.org/docs/messages.html
  16. * @see Mailer
  17. *
  18. * @method Mailer getMailer() returns mailer instance.
  19. *
  20. * @property integer $priority Priority value as integer in range: `1..5`, where 1 is the highest priority and
  21. * 5 is the lowest.
  22. * @property string $readReceiptTo Receipt receive email addresses. Note that the type of this property
  23. * differs in getter and setter. See [[getReadReceiptTo()]] and [[setReadReceiptTo()]] for details.
  24. * @property string $returnPath The bounce email address.
  25. * @property array|callable|\Swift_Signer $signature Signature specification. See [[addSignature()]] for
  26. * details on how it should be specified. This property is write-only.
  27. * @property \Swift_Message $swiftMessage Swift message instance. This property is read-only.
  28. *
  29. * @author Paul Klimov <klimov.paul@gmail.com>
  30. * @since 2.0
  31. */
  32. class Message extends BaseMessage
  33. {
  34. /**
  35. * @var \Swift_Message Swift message instance.
  36. */
  37. private $_swiftMessage;
  38. /**
  39. * @var \Swift_Signer[] attached signers
  40. */
  41. private $signers = [];
  42. /**
  43. * @return \Swift_Message Swift message instance.
  44. */
  45. public function getSwiftMessage()
  46. {
  47. if (!is_object($this->_swiftMessage)) {
  48. $this->_swiftMessage = $this->createSwiftMessage();
  49. }
  50. return $this->_swiftMessage;
  51. }
  52. /**
  53. * @inheritdoc
  54. */
  55. public function getCharset()
  56. {
  57. return $this->getSwiftMessage()->getCharset();
  58. }
  59. /**
  60. * @inheritdoc
  61. */
  62. public function setCharset($charset)
  63. {
  64. $this->getSwiftMessage()->setCharset($charset);
  65. return $this;
  66. }
  67. /**
  68. * @inheritdoc
  69. */
  70. public function getFrom()
  71. {
  72. return $this->getSwiftMessage()->getFrom();
  73. }
  74. /**
  75. * @inheritdoc
  76. */
  77. public function setFrom($from)
  78. {
  79. $this->getSwiftMessage()->setFrom($from);
  80. return $this;
  81. }
  82. /**
  83. * @inheritdoc
  84. */
  85. public function getReplyTo()
  86. {
  87. return $this->getSwiftMessage()->getReplyTo();
  88. }
  89. /**
  90. * @inheritdoc
  91. */
  92. public function setReplyTo($replyTo)
  93. {
  94. $this->getSwiftMessage()->setReplyTo($replyTo);
  95. return $this;
  96. }
  97. /**
  98. * @inheritdoc
  99. */
  100. public function getTo()
  101. {
  102. return $this->getSwiftMessage()->getTo();
  103. }
  104. /**
  105. * @inheritdoc
  106. */
  107. public function setTo($to)
  108. {
  109. $this->getSwiftMessage()->setTo($to);
  110. return $this;
  111. }
  112. /**
  113. * @inheritdoc
  114. */
  115. public function getCc()
  116. {
  117. return $this->getSwiftMessage()->getCc();
  118. }
  119. /**
  120. * @inheritdoc
  121. */
  122. public function setCc($cc)
  123. {
  124. $this->getSwiftMessage()->setCc($cc);
  125. return $this;
  126. }
  127. /**
  128. * @inheritdoc
  129. */
  130. public function getBcc()
  131. {
  132. return $this->getSwiftMessage()->getBcc();
  133. }
  134. /**
  135. * @inheritdoc
  136. */
  137. public function setBcc($bcc)
  138. {
  139. $this->getSwiftMessage()->setBcc($bcc);
  140. return $this;
  141. }
  142. /**
  143. * @inheritdoc
  144. */
  145. public function getSubject()
  146. {
  147. return $this->getSwiftMessage()->getSubject();
  148. }
  149. /**
  150. * @inheritdoc
  151. */
  152. public function setSubject($subject)
  153. {
  154. $this->getSwiftMessage()->setSubject($subject);
  155. return $this;
  156. }
  157. /**
  158. * @inheritdoc
  159. */
  160. public function setTextBody($text)
  161. {
  162. $this->setBody($text, 'text/plain');
  163. return $this;
  164. }
  165. /**
  166. * @inheritdoc
  167. */
  168. public function setHtmlBody($html)
  169. {
  170. $this->setBody($html, 'text/html');
  171. return $this;
  172. }
  173. /**
  174. * Sets the message body.
  175. * If body is already set and its content type matches given one, it will
  176. * be overridden, if content type miss match the multipart message will be composed.
  177. * @param string $body body content.
  178. * @param string $contentType body content type.
  179. */
  180. protected function setBody($body, $contentType)
  181. {
  182. $message = $this->getSwiftMessage();
  183. $oldBody = $message->getBody();
  184. $charset = $message->getCharset();
  185. if (empty($oldBody)) {
  186. $parts = $message->getChildren();
  187. $partFound = false;
  188. foreach ($parts as $key => $part) {
  189. if (!($part instanceof \Swift_Mime_Attachment)) {
  190. /* @var $part \Swift_Mime_MimePart */
  191. if ($part->getContentType() == $contentType) {
  192. $charset = $part->getCharset();
  193. unset($parts[$key]);
  194. $partFound = true;
  195. break;
  196. }
  197. }
  198. }
  199. if ($partFound) {
  200. reset($parts);
  201. $message->setChildren($parts);
  202. $message->addPart($body, $contentType, $charset);
  203. } else {
  204. $message->setBody($body, $contentType);
  205. }
  206. } else {
  207. $oldContentType = $message->getContentType();
  208. if ($oldContentType == $contentType) {
  209. $message->setBody($body, $contentType);
  210. } else {
  211. $message->setBody(null);
  212. $message->setContentType(null);
  213. $message->addPart($oldBody, $oldContentType, $charset);
  214. $message->addPart($body, $contentType, $charset);
  215. }
  216. }
  217. }
  218. /**
  219. * @inheritdoc
  220. */
  221. public function attach($fileName, array $options = [])
  222. {
  223. $attachment = \Swift_Attachment::fromPath($fileName);
  224. if (!empty($options['fileName'])) {
  225. $attachment->setFilename($options['fileName']);
  226. }
  227. if (!empty($options['contentType'])) {
  228. $attachment->setContentType($options['contentType']);
  229. }
  230. $this->getSwiftMessage()->attach($attachment);
  231. return $this;
  232. }
  233. /**
  234. * @inheritdoc
  235. */
  236. public function attachContent($content, array $options = [])
  237. {
  238. $attachment = \Swift_Attachment::newInstance($content);
  239. if (!empty($options['fileName'])) {
  240. $attachment->setFilename($options['fileName']);
  241. }
  242. if (!empty($options['contentType'])) {
  243. $attachment->setContentType($options['contentType']);
  244. }
  245. $this->getSwiftMessage()->attach($attachment);
  246. return $this;
  247. }
  248. /**
  249. * @inheritdoc
  250. */
  251. public function embed($fileName, array $options = [])
  252. {
  253. $embedFile = \Swift_EmbeddedFile::fromPath($fileName);
  254. if (!empty($options['fileName'])) {
  255. $embedFile->setFilename($options['fileName']);
  256. }
  257. if (!empty($options['contentType'])) {
  258. $embedFile->setContentType($options['contentType']);
  259. }
  260. return $this->getSwiftMessage()->embed($embedFile);
  261. }
  262. /**
  263. * @inheritdoc
  264. */
  265. public function embedContent($content, array $options = [])
  266. {
  267. $embedFile = \Swift_EmbeddedFile::newInstance($content);
  268. if (!empty($options['fileName'])) {
  269. $embedFile->setFilename($options['fileName']);
  270. }
  271. if (!empty($options['contentType'])) {
  272. $embedFile->setContentType($options['contentType']);
  273. }
  274. return $this->getSwiftMessage()->embed($embedFile);
  275. }
  276. /**
  277. * Sets message signature
  278. * @param array|callable|\Swift_Signer $signature signature specification.
  279. * See [[addSignature()]] for details on how it should be specified.
  280. * @return $this self reference.
  281. * @since 2.0.6
  282. */
  283. public function setSignature($signature)
  284. {
  285. if (!empty($this->signers)) {
  286. // clear previously set signers
  287. $swiftMessage = $this->getSwiftMessage();
  288. foreach ($this->signers as $signer) {
  289. $swiftMessage->detachSigner($signer);
  290. }
  291. $this->signers = [];
  292. }
  293. return $this->addSignature($signature);
  294. }
  295. /**
  296. * Adds message signature.
  297. * @param array|callable|\Swift_Signer $signature signature specification, this can be:
  298. *
  299. * - [[\Swift_Signer]] instance
  300. * - callable, which returns [[\Swift_Signer]] instance
  301. * - configuration array for the signer creation
  302. *
  303. * @return $this self reference
  304. * @throws InvalidConfigException on invalid signature configuration
  305. * @since 2.0.6
  306. */
  307. public function addSignature($signature)
  308. {
  309. if ($signature instanceof \Swift_Signer) {
  310. $signer = $signature;
  311. } elseif (is_callable($signature)) {
  312. $signer = call_user_func($signature);
  313. } elseif (is_array($signature)) {
  314. $signer = $this->createSwiftSigner($signature);
  315. } else {
  316. throw new InvalidConfigException('Signature should be instance of "Swift_Signer", callable or array configuration');
  317. }
  318. $this->getSwiftMessage()->attachSigner($signer);
  319. $this->signers[] = $signer;
  320. return $this;
  321. }
  322. /**
  323. * Creates signer from its configuration
  324. * @param array $signature signature configuration
  325. * @return \Swift_Signer signer instance
  326. * @throws InvalidConfigException on invalid configuration provided
  327. * @since 2.0.6
  328. */
  329. protected function createSwiftSigner($signature)
  330. {
  331. if (!isset($signature['type'])) {
  332. throw new InvalidConfigException('Signature configuration should contain "type" key');
  333. }
  334. switch (strtolower($signature['type'])) {
  335. case 'dkim' :
  336. $domain = ArrayHelper::getValue($signature, 'domain', null);
  337. $selector = ArrayHelper::getValue($signature, 'selector', null);
  338. if (isset($signature['key'])) {
  339. $privateKey = $signature['key'];
  340. } elseif (isset($signature['file'])) {
  341. $privateKey = file_get_contents(Yii::getAlias($signature['file']));
  342. } else {
  343. throw new InvalidConfigException("Either 'key' or 'file' signature option should be specified");
  344. }
  345. return new \Swift_Signers_DKIMSigner($privateKey, $domain, $selector);
  346. case 'opendkim' :
  347. $domain = ArrayHelper::getValue($signature, 'domain', null);
  348. $selector = ArrayHelper::getValue($signature, 'selector', null);
  349. if (isset($signature['key'])) {
  350. $privateKey = $signature['key'];
  351. } elseif (isset($signature['file'])) {
  352. $privateKey = file_get_contents(Yii::getAlias($signature['file']));
  353. } else {
  354. throw new InvalidConfigException("Either 'key' or 'file' signature option should be specified");
  355. }
  356. return new \Swift_Signers_OpenDKIMSigner($privateKey, $domain, $selector);
  357. default:
  358. throw new InvalidConfigException("Unrecognized signature type '{$signature['type']}'");
  359. }
  360. }
  361. /**
  362. * @inheritdoc
  363. */
  364. public function toString()
  365. {
  366. return $this->getSwiftMessage()->toString();
  367. }
  368. /**
  369. * Creates the Swift email message instance.
  370. * @return \Swift_Message email message instance.
  371. */
  372. protected function createSwiftMessage()
  373. {
  374. return new \Swift_Message();
  375. }
  376. // Headers setup :
  377. /**
  378. * Adds custom header value to the message.
  379. * Several invocations of this method with the same name will add multiple header values.
  380. * @param string $name header name.
  381. * @param string $value header value.
  382. * @return $this self reference.
  383. * @since 2.0.6
  384. */
  385. public function addHeader($name, $value)
  386. {
  387. $this->getSwiftMessage()->getHeaders()->addTextHeader($name, $value);
  388. return $this;
  389. }
  390. /**
  391. * Sets custom header value to the message.
  392. * @param string $name header name.
  393. * @param string|array $value header value or values.
  394. * @return $this self reference.
  395. * @since 2.0.6
  396. */
  397. public function setHeader($name, $value)
  398. {
  399. $headerSet = $this->getSwiftMessage()->getHeaders();
  400. if ($headerSet->has($name)) {
  401. $headerSet->remove($name);
  402. }
  403. foreach ((array)$value as $v) {
  404. $headerSet->addTextHeader($name, $v);
  405. }
  406. return $this;
  407. }
  408. /**
  409. * Returns all values for the specified header.
  410. * @param string $name header name.
  411. * @return array header values list.
  412. * @since 2.0.6
  413. */
  414. public function getHeader($name)
  415. {
  416. $headerSet = $this->getSwiftMessage()->getHeaders();
  417. if (!$headerSet->has($name)) {
  418. return [];
  419. }
  420. $headers = [];
  421. foreach ($headerSet->getAll($name) as $header) {
  422. $headers[] = $header->getValue();
  423. }
  424. return $headers;
  425. }
  426. // SwiftMessage shortcuts :
  427. /**
  428. * Set the return-path (the bounce address) of this message.
  429. * @param string $address the bounce email address.
  430. * @return $this self reference.
  431. * @since 2.0.6
  432. */
  433. public function setReturnPath($address)
  434. {
  435. $this->getSwiftMessage()->setReturnPath($address);
  436. return $this;
  437. }
  438. /**
  439. * Returns the return-path (the bounce address) of this message.
  440. * @return string the bounce email address.
  441. * @since 2.0.6
  442. */
  443. public function getReturnPath()
  444. {
  445. return $this->getSwiftMessage()->getReturnPath();
  446. }
  447. /**
  448. * Set the priority of this message.
  449. * @param integer $priority priority value, should be an integer in range: `1..5`,
  450. * where 1 is the highest priority and 5 is the lowest.
  451. * @return $this self reference.
  452. * @since 2.0.6
  453. */
  454. public function setPriority($priority)
  455. {
  456. $this->getSwiftMessage()->setPriority($priority);
  457. return $this;
  458. }
  459. /**
  460. * Returns the priority of this message.
  461. * @return integer priority value as integer in range: `1..5`,
  462. * where 1 is the highest priority and 5 is the lowest.
  463. * @since 2.0.6
  464. */
  465. public function getPriority()
  466. {
  467. return $this->getSwiftMessage()->getPriority();
  468. }
  469. /**
  470. * Sets the ask for a delivery receipt from the recipient to be sent to $addresses.
  471. * @param string|array $addresses receipt receive email address(es).
  472. * @return $this self reference.
  473. * @since 2.0.6
  474. */
  475. public function setReadReceiptTo($addresses)
  476. {
  477. $this->getSwiftMessage()->setReadReceiptTo($addresses);
  478. return $this;
  479. }
  480. /**
  481. * Get the addresses to which a read-receipt will be sent.
  482. * @return string receipt receive email addresses.
  483. * @since 2.0.6
  484. */
  485. public function getReadReceiptTo()
  486. {
  487. return $this->getSwiftMessage()->getReadReceiptTo();
  488. }
  489. }