Code Coverage
 
Lines
Functions and Methods
Classes and Traits
Total
100.00% covered (success)
100.00%
36 / 36
100.00% covered (success)
100.00%
2 / 2
CRAP
100.00% covered (success)
100.00%
1 / 1
Mailgun
100.00% covered (success)
100.00%
36 / 36
100.00% covered (success)
100.00%
2 / 2
13
100.00% covered (success)
100.00%
1 / 1
 createClient
100.00% covered (success)
100.00%
8 / 8
100.00% covered (success)
100.00%
1 / 1
4
 send
100.00% covered (success)
100.00%
28 / 28
100.00% covered (success)
100.00%
1 / 1
9
1<?php
2/**
3 * Pop PHP Framework (https://www.popphp.org/)
4 *
5 * @link       https://github.com/popphp/popphp-framework
6 * @author     Nick Sagona, III <dev@noladev.com>
7 * @copyright  Copyright (c) 2009-2026 NOLA Interactive, LLC.
8 * @license    https://www.popphp.org/license     New BSD License
9 */
10
11/**
12 * @namespace
13 */
14namespace Pop\Mail\Transport;
15
16use Pop\Http\Client;
17use Pop\Mail\Api\AbstractHttp;
18use Pop\Mail\Message;
19
20/**
21 * Mailgun API transport class
22 *
23 * @category   Pop
24 * @package    Pop\Mail
25 * @author     Nick Sagona, III <dev@noladev.com>
26 * @copyright  Copyright (c) 2009-2026 NOLA Interactive, LLC.
27 * @license    https://www.popphp.org/license     New BSD License
28 * @version    4.0.7
29 */
30class Mailgun extends AbstractHttp implements TransportInterface
31{
32
33    /**
34     * Create the API client
35     *
36     * @param  array|string $options
37     * @throws Exception|Client\Exception|\Pop\Mail\Api\Exception
38     * @return Mailgun
39     */
40    public function createClient(array|string $options): Mailgun
41    {
42        if (is_string($options)) {
43            $options = $this->parseOptions($options);
44        }
45
46        if (!isset($options['api_url']) || !isset($options['api_key'])) {
47            throw new Exception('Error: The required client options were not provided.');
48        }
49
50        $request = new Client\Request($options['api_url'], 'POST');
51        $request->addHeader('Authorization', 'Basic ' . base64_encode('api:' . $options['api_key']));
52
53        $this->client = new Client($request, new Client\Handler\Curl(), ['force_custom_method' => true]);
54
55        return $this;
56    }
57
58    /**
59     * Send the message
60     *
61     * @param  Message $message
62     * @return mixed
63     */
64    public function send(Message $message): mixed
65    {
66        $fields         = [];
67        $headers        = $message->getHeaders();
68        $parts          = $message->getParts();
69        $primaryHeaders = ['Subject', 'To', 'From', 'CC', 'BCC'];
70
71        foreach ($headers as $header => $value) {
72            if (!in_array($header, $primaryHeaders)) {
73                $header = 'h:' . $header;
74            } else {
75                $header = strtolower($header);
76            }
77            $fields[$header] = $value;
78        }
79
80        $i = 0;
81
82        foreach ($parts as $part) {
83            if ($part instanceof Message\Text) {
84                $fields['text'] = $part->getBody();
85            } else if ($part instanceof Message\Html) {
86                $fields['html'] = $part->getBody();
87            } else if ($part instanceof Message\Attachment) {
88                $contentType = $part->getContentType();
89                if (str_contains($contentType, ';')) {
90                    $contentType = trim(substr($contentType, 0, strpos($contentType, ';')));
91                }
92                $fields['attachment[' . $i . ']'] = curl_file_create($part->getFilename(), $contentType, $part->getBasename());
93                $i++;
94            }
95        }
96
97        $this->client->setData($fields);
98
99        if ($i > 0) {
100            $this->client->getRequest()->addHeader('Content-Type', 'multipart/form-data');
101            $this->client->getRequest()
102                ->setNoContentLength(true)
103                ->setRawData(true);
104        }
105
106        return $this->client->send();
107    }
108
109}