PluginProbe ʕ •ᴥ•ʔ
WP Mail SMTP by WPForms – The Most Popular SMTP and Email Log Plugin / 4.3.0
WP Mail SMTP by WPForms – The Most Popular SMTP and Email Log Plugin v4.3.0
0.9.6 1.0.0 1.0.1 1.0.2 1.1.0 1.2.0 1.2.1 1.2.2 1.2.3 1.2.4 1.2.5 1.3.0 1.3.1 1.3.2 1.3.3 1.4.0 1.4.1 1.4.2 1.5.0 1.5.1 1.5.2 1.6.0 1.6.2 1.7.0 1.7.1 1.8.0 1.8.1 1.9.0 2.0.0 2.0.1 2.1.1 2.2.1 2.3.1 2.4.0 2.5.0 2.5.1 2.6.0 2.7.0 2.8.0 2.9.0 3.0.1 3.0.2 3.0.3 3.1.0 3.10.0 3.11.0 3.11.1 3.2.0 3.2.1 3.3.0 3.4.0 3.5.0 3.5.1 3.5.2 3.6.1 3.7.0 3.8.0 3.8.2 3.9.0 4.0.1 4.1.0 4.1.1 4.2.0 4.3.0 4.4.0 4.5.0 4.6.0 4.7.0 4.7.1 4.8.0 trunk 0.10.0 0.10.1 0.11.1 0.11.2 0.3.1 0.3.2 0.4 0.4.1 0.4.2 0.5.0 0.5.1 0.5.2 0.6 0.7 0.8 0.8.2 0.8.3 0.8.4 0.8.5 0.8.6 0.8.7 0.9.0 0.9.1 0.9.2 0.9.3 0.9.4 0.9.5
wp-mail-smtp / src / Providers / ElasticEmail / Mailer.php
wp-mail-smtp / src / Providers / ElasticEmail Last commit date
Mailer.php 1 year ago Options.php 1 year ago
Mailer.php
480 lines
1 <?php
2
3 namespace WPMailSMTP\Providers\ElasticEmail;
4
5 use WPMailSMTP\Helpers\Helpers;
6 use WPMailSMTP\Providers\MailerAbstract;
7 use WPMailSMTP\WP;
8
9 /**
10 * Class Mailer.
11 *
12 * @since 4.3.0
13 */
14 class Mailer extends MailerAbstract {
15
16 /**
17 * Which response code from HTTP provider is considered to be successful?
18 *
19 * @since 4.3.0
20 *
21 * @var int
22 */
23 protected $email_sent_code = 200;
24
25
26 /**
27 * URL to make an API request to.
28 *
29 * @since 4.3.0
30 *
31 * @var string
32 */
33 protected $url = 'https://api.elasticemail.com/v4/emails/transactional';
34
35 /**
36 * Mailer constructor.
37 *
38 * @since 4.3.0
39 *
40 * @param MailCatcherInterface $phpmailer The MailCatcher object.
41 * @param ConnectionInterface $connection The Connection object.
42 */
43 public function __construct( $phpmailer, $connection = null ) {
44
45 // We want to prefill everything from MailCatcher class, which extends PHPMailer.
46 parent::__construct( $phpmailer, $connection );
47
48 // Set mailer specific headers.
49 $this->set_header( 'Accept', 'application/json' );
50 $this->set_header( 'Content-Type', 'application/json' );
51 $this->set_header( 'X-ElasticEmail-ApiKey', $this->connection_options->get( $this->mailer, 'api_key' ) );
52 }
53
54 /**
55 * Redefine the way custom headers are processed for this mailer - they should be in body.
56 *
57 * @since 4.3.0
58 *
59 * @param array $headers Headers array.
60 */
61 public function set_headers( $headers ) {
62
63 foreach ( $headers as $header ) {
64 $name = isset( $header[0] ) ? $header[0] : false;
65 $value = isset( $header[1] ) ? $header[1] : false;
66
67 $this->set_body_header( $name, $value );
68 }
69
70 // Add custom header.
71 $this->set_body_header( 'X-Mailer', 'WPMailSMTP/Mailer/' . $this->mailer . ' ' . WPMS_PLUGIN_VER );
72 }
73
74 /**
75 * This mailer supports email-related custom headers inside a body of the message.
76 *
77 * @since 4.3.0
78 *
79 * @param string $name Header name.
80 * @param string $value Header value.
81 */
82 public function set_body_header( $name, $value ) {
83
84 $name = sanitize_text_field( $name );
85
86 if ( empty( $name ) ) {
87 return;
88 }
89
90 $this->set_body_param(
91 [
92 'Content' => [
93 'Headers' => [
94 $name => $this->sanitize_header_value( $name, $value ),
95 ],
96 ],
97 ]
98 );
99 }
100
101 /**
102 * Set the From information for an email.
103 *
104 * @since 4.3.0
105 *
106 * @param string $email The sender email address.
107 * @param string $name The sender name.
108 */
109 public function set_from( $email, $name ) {
110
111 if ( ! filter_var( $email, FILTER_VALIDATE_EMAIL ) ) {
112 return;
113 }
114
115 $this->set_body_param(
116 [
117 'Content' => [
118 'From' => $this->address_format( [ $email, $name ] ),
119 ],
120 ]
121 );
122 }
123
124 /**
125 * Set email recipients: to, cc, bcc.
126 *
127 * @since 4.3.0
128 *
129 * @param array $recipients Email recipients.
130 */
131 public function set_recipients( $recipients ) { // phpcs:ignore Generic.Metrics.CyclomaticComplexity.TooHigh
132
133 if ( empty( $recipients ) ) {
134 return;
135 }
136
137 // Allow only these recipient types.
138 $recipient_mappings = [
139 'to' => 'To',
140 'cc' => 'CC',
141 'bcc' => 'BCC',
142 ];
143
144 $allowed_types = array_keys( $recipient_mappings );
145 $data = [];
146
147 foreach ( $recipients as $type => $emails ) {
148 if (
149 ! in_array( $type, $allowed_types, true ) ||
150 empty( $emails ) ||
151 ! is_array( $emails )
152 ) {
153 continue;
154 }
155
156 $field = $recipient_mappings[ $type ];
157
158 // Iterate over all emails for each type.
159 // There might be multiple cc/to/bcc emails.
160 foreach ( $emails as $email ) {
161 if ( ! isset( $email[0] ) || ! filter_var( $email[0], FILTER_VALIDATE_EMAIL ) ) {
162 continue;
163 }
164
165 $data[ $field ][] = $this->address_format( $email );
166 }
167 }
168
169 if ( ! empty( $data ) ) {
170 $this->set_body_param(
171 [
172 'Recipients' => $data,
173 ]
174 );
175 }
176 }
177
178 /**
179 * Set the Reply To information for an email.
180 *
181 * @since 4.3.0
182 *
183 * @param array $emails Reply To email addresses.
184 */
185 public function set_reply_to( $emails ) {
186
187 if ( empty( $emails ) ) {
188 return;
189 }
190
191 $data = [];
192
193 foreach ( $emails as $email ) {
194 if ( ! isset( $email[0] ) || ! filter_var( $email[0], FILTER_VALIDATE_EMAIL ) ) {
195 continue;
196 }
197
198 $data[] = $this->address_format( $email );
199 }
200
201 if ( ! empty( $data ) ) {
202 $this->set_body_param(
203 [
204 'Content' => [
205 'ReplyTo' => $data[0],
206 ],
207 ]
208 );
209 }
210 }
211
212 /**
213 * Set email subject.
214 *
215 * @since 4.3.0
216 *
217 * @param string $subject Email subject.
218 */
219 public function set_subject( $subject ) {
220
221 $this->set_body_param(
222 [
223 'Content' => [
224 'Subject' => $subject,
225 ],
226 ]
227 );
228 }
229
230 /**
231 * Set email content.
232 *
233 * @since 4.3.0
234 *
235 * @param string|array $content Email content.
236 */
237 public function set_content( $content ) {
238
239 if ( empty( $content ) ) {
240 return;
241 }
242
243 $data = [];
244
245 if ( is_array( $content ) ) {
246 if ( ! empty( $content['text'] ) ) {
247 $data[] = [
248 'ContentType' => 'PlainText',
249 'Content' => $content['text'],
250 ];
251 }
252
253 if ( ! empty( $content['html'] ) ) {
254 $data[] = [
255 'ContentType' => 'HTML',
256 'Content' => $content['html'],
257 ];
258 }
259 } else {
260 if ( $this->phpmailer->ContentType === 'text/plain' ) {
261 $data[] = [
262 'ContentType' => 'PlainText',
263 'Content' => $content,
264 ];
265 } else {
266 $data[] = [
267 'ContentType' => 'HTML',
268 'Content' => $content,
269 ];
270 }
271 }
272
273 $this->set_body_param(
274 [
275 'Content' => [
276 'Body' => $data,
277 ],
278 ]
279 );
280 }
281
282 /**
283 * Set attachments for an email.
284 *
285 * @since 4.3.0
286 *
287 * @param array $attachments Attachments array.
288 */
289 public function set_attachments( $attachments ) { // phpcs:ignore Generic.Metrics.CyclomaticComplexity.TooHigh
290
291 if ( empty( $attachments ) ) {
292 return;
293 }
294
295 $data = $this->prepare_attachments( $attachments );
296
297 if ( ! empty( $data ) ) {
298 $this->set_body_param(
299 [
300 'Content' => [
301 'Attachments' => $data,
302 ],
303 ]
304 );
305 }
306 }
307
308 /**
309 * Prepare attachments data for SendLayer API.
310 *
311 * @since 4.3.0
312 *
313 * @param array $attachments Array of attachments.
314 *
315 * @return array
316 */
317 protected function prepare_attachments( $attachments ) {
318
319 $data = [];
320
321 foreach ( $attachments as $attachment ) {
322 $file = $this->get_attachment_file_content( $attachment );
323
324 if ( $file === false ) {
325 continue;
326 }
327
328 $filetype = str_replace( ';', '', trim( $attachment[4] ) );
329
330 $data[] = [
331 'Name' => empty( $attachment[2] ) ? 'file-' . wp_hash( microtime() ) . '.' . $filetype : trim( $attachment[2] ), // phpcs:ignore WordPress.PHP.DiscouragedPHPFunctions.obfuscation_base64_encode
332 'BinaryContent' => base64_encode( $file ),
333 'ContentType' => $attachment[4],
334 ];
335 }
336
337 return $data;
338 }
339
340 /**
341 * Doesn't support this.
342 * So we do nothing.
343 *
344 * @since 4.3.0
345 *
346 * @param string $email Return Path email address.
347 */
348 public function set_return_path( $email ) {}
349
350 /**
351 * Redefine the way email body is returned.
352 * By default, we are sending an array of data.
353 * ElasticEmail requires a JSON, so we encode the body.
354 *
355 * @since 4.3.0
356 */
357 public function get_body() {
358
359 $body = parent::get_body();
360
361 return wp_json_encode( $body );
362 }
363
364 /**
365 * We might need to do something after the email was sent to the API.
366 * In this method we preprocess the response from the API.
367 *
368 * @since 4.3.0
369 *
370 * @param mixed $response Response data.
371 */
372 protected function process_response( $response ) {
373
374 parent::process_response( $response );
375
376 if (
377 ! is_wp_error( $response ) &&
378 ! empty( $this->response['body'] ) &&
379 ! empty( $this->response['body']->TransactionID )
380 ) {
381 $this->phpmailer->addCustomHeader( 'X-Msg-ID', $this->response['body']->TransactionID );
382 $this->verify_sent_status = true;
383 }
384 }
385
386 /**
387 * Whether the email is sent or not.
388 * We check response code and a non-empty `TransactionID` field in the response body.
389 *
390 * @since 4.3.0
391 *
392 * @return bool
393 */
394 public function is_email_sent() {
395
396 $is_sent = false;
397
398 if (
399 wp_remote_retrieve_response_code( $this->response ) === $this->email_sent_code &&
400 ! empty( $this->response['body'] ) &&
401 ! empty( $this->response['body']->TransactionID )
402 ) {
403 $is_sent = true;
404 }
405
406 // phpcs:disable WPForms.Comments.Since.MissingPhpDoc, WPForms.PHP.ValidateHooks.InvalidHookName
407
408 /** This filter is documented in src/Providers/MailerAbstract.php. */
409 return apply_filters( 'wp_mail_smtp_providers_mailer_is_email_sent', $is_sent, $this->mailer );
410 // phpcs:enable WPForms.Comments.Since.MissingPhpDoc, WPForms.PHP.ValidateHooks.InvalidHookName
411 }
412
413 /**
414 * Get an Elastic Email specific response with a helpful error.
415 *
416 * @since 4.3.0
417 *
418 * @return string
419 */
420 public function get_response_error() { // phpcs:ignore Generic.Metrics.NestingLevel.MaxExceeded, Generic.Metrics.CyclomaticComplexity.TooHigh
421
422 $error_text[] = $this->error_message;
423
424 if ( ! empty( $this->response ) ) {
425 $body = wp_remote_retrieve_body( $this->response );
426
427 // phpcs:disable WordPress.NamingConventions.ValidVariableName.UsedPropertyNotSnakeCase
428 if ( ! empty( $body->Error ) ) {
429 $error_text[] = Helpers::format_error_message( $body->Error );
430 } else {
431 $error_text[] = WP::wp_remote_get_response_error_message( $this->response );
432 }
433 // phpcs:enable WordPress.NamingConventions.ValidVariableName.UsedPropertyNotSnakeCase
434 }
435
436 return implode( WP::EOL, array_map( 'esc_textarea', array_filter( $error_text ) ) );
437 }
438
439 /**
440 * Whether the mailer has all its settings correctly set up and saved.
441 *
442 * @since 4.3.0
443 *
444 * @return bool
445 */
446 public function is_mailer_complete() {
447
448 $options = $this->connection_options->get_group( $this->mailer );
449
450 if ( ! empty( $options['api_key'] ) ) {
451 return true;
452 }
453
454 return false;
455 }
456
457 /**
458 * Prepare address param.
459 *
460 * @since 4.3.0
461 *
462 * @param array $address Address array.
463 *
464 * @return array
465 */
466 private function address_format( $address ) {
467
468 $email = isset( $address[0] ) ? $address[0] : false;
469 $name = isset( $address[1] ) ? $address[1] : false;
470
471 $result = $email;
472
473 if ( ! empty( $name ) ) {
474 $result = "{$name} <{$email}>";
475 }
476
477 return $result;
478 }
479 }
480