Message.php 8.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250
  1. <?php
  2. declare(strict_types=1);
  3. /*
  4. * Copyright (C) 2013 Mailgun
  5. *
  6. * This software may be modified and distributed under the terms
  7. * of the MIT license. See the LICENSE file for details.
  8. */
  9. namespace Mailgun\Api;
  10. use Exception;
  11. use Mailgun\Assert;
  12. use Mailgun\Exception\InvalidArgumentException;
  13. use Mailgun\Message\BatchMessage;
  14. use Mailgun\Model\Message\QueueStatusResponse;
  15. use Mailgun\Model\Message\SendResponse;
  16. use Mailgun\Model\Message\ShowResponse;
  17. use Psr\Http\Client\ClientExceptionInterface;
  18. use Psr\Http\Message\ResponseInterface;
  19. use RuntimeException;
  20. /**
  21. * @see https://documentation.mailgun.com/en/latest/api-sending.html
  22. *
  23. * @author Tobias Nyholm <tobias.nyholm@gmail.com>
  24. */
  25. class Message extends HttpApi
  26. {
  27. /**
  28. * @param string $domain
  29. * @param bool $autoSend
  30. * @return BatchMessage
  31. */
  32. public function getBatchMessage(string $domain, bool $autoSend = true): BatchMessage
  33. {
  34. return new BatchMessage($this, $domain, $autoSend);
  35. }
  36. /**
  37. * @see https://documentation.mailgun.com/en/latest/api-sending.html#sending
  38. * @param string $domain
  39. * @param array $params
  40. * @param array $requestHeaders
  41. * @return SendResponse|ResponseInterface
  42. * @throws ClientExceptionInterface
  43. */
  44. public function send(string $domain, array $params, array $requestHeaders = [])
  45. {
  46. Assert::string($domain);
  47. Assert::notEmpty($domain);
  48. Assert::notEmpty($params);
  49. $postDataMultipart = [];
  50. $fields = ['attachment', 'inline'];
  51. foreach ($fields as $fieldName) {
  52. if (!isset($params[$fieldName])) {
  53. continue;
  54. }
  55. Assert::isArray($params[$fieldName]);
  56. foreach ($params[$fieldName] as $file) {
  57. $postDataMultipart[] = $this->prepareFile($fieldName, $file);
  58. }
  59. unset($params[$fieldName]);
  60. }
  61. $postDataMultipart = array_merge($this->prepareMultipartParameters($params), $postDataMultipart);
  62. try {
  63. $response = $this->httpPostRaw(sprintf('/v3/%s/messages', $domain), $postDataMultipart, $requestHeaders);
  64. } catch (Exception $exception) {
  65. throw new RuntimeException($exception->getMessage());
  66. } finally {
  67. $this->closeResources($postDataMultipart);
  68. }
  69. return $this->hydrateResponse($response, SendResponse::class);
  70. }
  71. /**
  72. * @see https://documentation.mailgun.com/en/latest/api-sending.html#sending
  73. * @param string $domain
  74. * @param array $recipients with all you send emails to. Including bcc and cc
  75. * @param string $message Message filepath or content
  76. * @param array $params
  77. * @param array $requestHeaders
  78. * @return SendResponse|ResponseInterface
  79. * @throws ClientExceptionInterface
  80. */
  81. public function sendMime(string $domain, array $recipients, string $message, array $params, array $requestHeaders = [])
  82. {
  83. Assert::string($domain);
  84. Assert::notEmpty($domain);
  85. Assert::notEmpty($recipients);
  86. Assert::notEmpty($message);
  87. Assert::nullOrIsArray($params);
  88. $params['to'] = $recipients;
  89. $postDataMultipart = $this->prepareMultipartParameters($params);
  90. if (strlen($message) < PHP_MAXPATHLEN && is_file($message)) {
  91. $fileData = ['filePath' => $message];
  92. } else {
  93. $fileData = [
  94. 'fileContent' => $message,
  95. 'filename' => 'message',
  96. ];
  97. }
  98. $postDataMultipart[] = $this->prepareFile('message', $fileData);
  99. try {
  100. $response = $this->httpPostRaw(sprintf('/v3/%s/messages.mime', $domain), $postDataMultipart, $requestHeaders);
  101. } catch (Exception $exception) {
  102. throw new RuntimeException($exception->getMessage());
  103. } finally {
  104. $this->closeResources($postDataMultipart);
  105. }
  106. return $this->hydrateResponse($response, SendResponse::class);
  107. }
  108. /**
  109. * Get stored message.
  110. * @see https://documentation.mailgun.com/en/latest/api-sending.html#retrieving-stored-messages
  111. * @param string $url
  112. * @param bool $rawMessage if true we will use "Accept: message/rfc2822" header
  113. * @param array $requestHeaders
  114. * @return ShowResponse|ResponseInterface
  115. * @throws ClientExceptionInterface
  116. */
  117. public function show(string $url, bool $rawMessage = false, array $requestHeaders = [])
  118. {
  119. Assert::notEmpty($url);
  120. $headers = [];
  121. if ($rawMessage) {
  122. $headers['Accept'] = 'message/rfc2822';
  123. }
  124. if (!empty($requestHeaders)) {
  125. $headers = array_merge($headers, $requestHeaders);
  126. }
  127. $response = $this->httpGet($url, [], $headers);
  128. return $this->hydrateResponse($response, ShowResponse::class);
  129. }
  130. /**
  131. * Get messages queue status
  132. * @see https://documentation.mailgun.com/docs/mailgun/api-reference/openapi-final/tag/Messages/#tag/Messages/operation/httpapi.(*LegacyHttpApi).GetDomainSendingQueues-fm-70
  133. * @param string $domain
  134. * @param array $requestHeaders
  135. * @return QueueStatusResponse
  136. * @throws ClientExceptionInterface
  137. */
  138. public function getMessageQueueStatus(string $domain, array $requestHeaders = [])
  139. {
  140. Assert::notEmpty($domain);
  141. $response = $this->httpGet(sprintf('/v3/domains/%s/sending_queues', $domain), [], $requestHeaders);
  142. return $this->hydrateResponse($response, QueueStatusResponse::class);
  143. }
  144. /**
  145. * @param string $domain
  146. * @param string $storageId
  147. * @param array $requestHeaders
  148. * @return ShowResponse
  149. * @throws ClientExceptionInterface
  150. */
  151. public function retrieveStoredMessage(string $domain, string $storageId, array $requestHeaders = []): ShowResponse
  152. {
  153. Assert::notEmpty($domain);
  154. Assert::notEmpty($storageId);
  155. $response = $this->httpGet(sprintf('/v3/domains/%s/messages/%s', $domain, $storageId), [], $requestHeaders);
  156. return $this->hydrateResponse($response, ShowResponse::class);
  157. }
  158. /**
  159. * @param array $filePath array('fileContent' => 'content') or array('filePath' => '/foo/bar')
  160. *
  161. * @throws InvalidArgumentException
  162. */
  163. private function prepareFile(string $fieldName, array $filePath): array
  164. {
  165. $filename = $filePath['filename'] ?? null;
  166. if (isset($filePath['fileContent'])) {
  167. // File from memory
  168. $resource = fopen('php://temp', 'rb+');
  169. fwrite($resource, $filePath['fileContent']);
  170. rewind($resource);
  171. } elseif (isset($filePath['filePath'])) {
  172. // File form path
  173. $path = $filePath['filePath'];
  174. // Remove leading @ symbol
  175. if (0 === strpos($path, '@')) {
  176. $path = substr($path, 1);
  177. }
  178. $resource = fopen($path, 'rb');
  179. } else {
  180. throw new InvalidArgumentException('When using a file you need to specify parameter "fileContent" or "filePath"');
  181. }
  182. return [
  183. 'name' => $fieldName,
  184. 'content' => $resource,
  185. 'filename' => $filename,
  186. ];
  187. }
  188. /**
  189. * Prepare multipart parameters. Make sure each POST parameter is split into an array with 'name' and 'content' keys.
  190. */
  191. private function prepareMultipartParameters(array $params): array
  192. {
  193. $postDataMultipart = [];
  194. foreach ($params as $key => $value) {
  195. // If $value is not an array we cast it to an array
  196. foreach ((array) $value as $subValue) {
  197. if (is_int($subValue)) {
  198. $subValue = (string) $subValue;
  199. }
  200. $postDataMultipart[] = [
  201. 'name' => $key,
  202. 'content' => $subValue,
  203. ];
  204. }
  205. }
  206. return $postDataMultipart;
  207. }
  208. /**
  209. * Close open resources.
  210. */
  211. private function closeResources(array $params): void
  212. {
  213. foreach ($params as $param) {
  214. if (is_array($param) && array_key_exists('content', $param) && is_resource($param['content'])) {
  215. fclose($param['content']);
  216. }
  217. }
  218. }
  219. }