Code Coverage |
||||||||||
Lines |
Functions and Methods |
Classes and Traits |
||||||||
Total | |
100.00% |
95 / 95 |
|
100.00% |
2 / 2 |
CRAP | |
100.00% |
1 / 1 |
Sendgrid | |
100.00% |
95 / 95 |
|
100.00% |
2 / 2 |
26 | |
100.00% |
1 / 1 |
createClient | |
100.00% |
8 / 8 |
|
100.00% |
1 / 1 |
4 | |||
send | |
100.00% |
87 / 87 |
|
100.00% |
1 / 1 |
22 |
1 | <?php |
2 | /** |
3 | * Pop PHP Framework (http://www.popphp.org/) |
4 | * |
5 | * @link https://github.com/popphp/popphp-framework |
6 | * @author Nick Sagona, III <dev@nolainteractive.com> |
7 | * @copyright Copyright (c) 2009-2024 NOLA Interactive, LLC. (http://www.nolainteractive.com) |
8 | * @license http://www.popphp.org/license New BSD License |
9 | */ |
10 | |
11 | /** |
12 | * @namespace |
13 | */ |
14 | namespace Pop\Mail\Transport; |
15 | |
16 | use Pop\Http\Client; |
17 | use Pop\Http\Auth; |
18 | use Pop\Mail\Api\AbstractHttp; |
19 | use Pop\Mail\Message; |
20 | use Pop\Mail\Message\Text; |
21 | use Pop\Mail\Message\Html; |
22 | use Pop\Mail\Message\Attachment; |
23 | |
24 | /** |
25 | * Sendgrid API transport class |
26 | * |
27 | * @category Pop |
28 | * @package Pop\Mail |
29 | * @author Nick Sagona, III <dev@nolainteractive.com> |
30 | * @copyright Copyright (c) 2009-2024 NOLA Interactive, LLC. (http://www.nolainteractive.com) |
31 | * @license http://www.popphp.org/license New BSD License |
32 | * @version 4.0.0 |
33 | */ |
34 | class Sendgrid extends AbstractHttp implements TransportInterface |
35 | { |
36 | |
37 | /** |
38 | * Create the API client |
39 | * |
40 | * @param array|string $options |
41 | * @throws Exception|Client\Exception|\Pop\Mail\Api\Exception |
42 | * @return Sendgrid |
43 | */ |
44 | public function createClient(array|string $options): Sendgrid |
45 | { |
46 | if (is_string($options)) { |
47 | $options = $this->parseOptions($options); |
48 | } |
49 | |
50 | if (!isset($options['api_url']) || !isset($options['api_key'])) { |
51 | throw new Exception('Error: The required client options were not provided.'); |
52 | } |
53 | |
54 | $request = new Client\Request($options['api_url'], 'POST'); |
55 | $request->createAsJson(); |
56 | $this->client = new Client($request, Auth::createBearer($options['api_key']), new Client\Handler\Stream()); |
57 | |
58 | return $this; |
59 | } |
60 | |
61 | /** |
62 | * Send the message |
63 | * |
64 | * @param Message $message |
65 | * @return mixed |
66 | */ |
67 | public function send(Message $message): mixed |
68 | { |
69 | $headers = $message->getHeaders(); |
70 | $parts = $message->getParts(); |
71 | $personalHeaders = ['From', 'Reply-To', 'Subject', 'To', 'CC', 'BCC']; |
72 | $fields = [ |
73 | 'personalizations' => [], |
74 | 'content' => [], |
75 | 'subject' => $message->getSubject() |
76 | ]; |
77 | |
78 | $toAddresses = $message->getTo(); |
79 | $ccAddresses = $message->getCc(); |
80 | $bccAddresses = $message->getBcc(); |
81 | $fromAddress = $message->getFrom(); |
82 | $replyToAddress = $message->getReplyTo(); |
83 | |
84 | $to = []; |
85 | $cc = []; |
86 | $bcc = []; |
87 | |
88 | foreach ($toAddresses as $email => $name) { |
89 | if (!empty($name)) { |
90 | $to[] = [ |
91 | 'email' => $email, |
92 | 'name' => $name |
93 | ]; |
94 | } else { |
95 | $to[] = [ |
96 | 'email' => $email |
97 | ]; |
98 | } |
99 | } |
100 | |
101 | foreach ($ccAddresses as $email => $name) { |
102 | if (!empty($name)) { |
103 | $cc[] = [ |
104 | 'email' => $email, |
105 | 'name' => $name |
106 | ]; |
107 | } else { |
108 | $cc[] = [ |
109 | 'email' => $email |
110 | ]; |
111 | } |
112 | } |
113 | |
114 | foreach ($bccAddresses as $email => $name) { |
115 | if (!empty($name)) { |
116 | $bcc[] = [ |
117 | 'email' => $email, |
118 | 'name' => $name |
119 | ]; |
120 | } else { |
121 | $bcc[] = [ |
122 | 'email' => $email |
123 | ]; |
124 | } |
125 | } |
126 | |
127 | if (!empty($to)) { |
128 | $fields['personalizations'][] = ['to' => $to]; |
129 | } |
130 | if (!empty($cc)) { |
131 | $fields['personalizations'][] = ['cc' => $cc]; |
132 | } |
133 | if (!empty($bcc)) { |
134 | $fields['personalizations'][] = ['bcc' => $bcc]; |
135 | } |
136 | |
137 | $fields['from'] = ['email' => array_key_first($fromAddress)]; |
138 | |
139 | |
140 | if (!empty($fromAddress[$fields['from']['email']])) { |
141 | $fields['from']['name'] = $fromAddress[$fields['from']['email']]; |
142 | } |
143 | |
144 | if (!empty($replyToAddress)) { |
145 | $fields['reply_to'] = ['email' => array_key_first($replyToAddress)]; |
146 | if (!empty($replyToAddress[$fields['reply_to']['email']])) { |
147 | $fields['reply_to']['name'] = $replyToAddress[$fields['reply_to']['email']]; |
148 | } |
149 | } else { |
150 | $fields['reply_to'] = $fields['from']; |
151 | } |
152 | |
153 | foreach ($headers as $header => $value) { |
154 | if (!in_array($header, $personalHeaders)) { |
155 | if (!isset($fields['headers'])) { |
156 | $fields['headers'] = []; |
157 | } |
158 | $fields['headers'][$header] = $value; |
159 | } |
160 | } |
161 | |
162 | foreach ($parts as $part) { |
163 | if ($part instanceof Text) { |
164 | $fields['content'][] = [ |
165 | 'type' => 'text/plain', |
166 | 'value' => $part->getBody() |
167 | ]; |
168 | } else if ($part instanceof Html) { |
169 | $fields['content'][] = [ |
170 | 'type' => 'text/html', |
171 | 'value' => $part->getBody() |
172 | ]; |
173 | } else if ($part instanceof Attachment) { |
174 | if (!isset($fields['attachments'])) { |
175 | $fields['attachments'] = []; |
176 | } |
177 | $contentType = $part->getContentType(); |
178 | if (str_contains($contentType, ';')) { |
179 | $contentType = trim(substr($contentType, 0, strpos($contentType, ';'))); |
180 | } |
181 | $fields['attachments'][] = [ |
182 | 'content' => base64_encode(file_get_contents($part->getFilename())), |
183 | 'type' => $contentType, |
184 | 'filename' => $part->getBasename(), |
185 | 'disposition' => 'attachment' |
186 | ]; |
187 | } |
188 | } |
189 | |
190 | $this->client->setData($fields); |
191 | return $this->client->send(); |
192 | } |
193 | |
194 | } |