/var/www/html_us/wp-content/plugins/wp-smtp/src/Mail/Connectors/ConnectorPostmark.php


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
<?php
/**
 * ConnectorPostmark class for managing Postmark SMTP connection settings.
 *
 * @since   1.2.0
 * @package SolidWP\Mail\Connectors
 */

namespace SolidWP\Mail\Connectors;

use 
SolidWP\Mail\Contracts\Api_Connector;
use 
WP_Error;

class 
ConnectorPostmark extends ConnectorSMTP implements Api_Connector {

    
/**
     * Postmark API endpoint for sending emails.
     *
     * @since 2.1.3
     * @var string
     */
    
const API_ENDPOINT 'https://api.postmarkapp.com/email';

    
/**
     * ConnectorPostmark constructor.
     * Initializes the Postmark connector with default SMTP settings.
     *
     * @param array $data Optional. Configuration data for the connector.
     *
     * @since 1.2.0
     */
    
public function __construct( array $data = [] ) {
        
parent::__construct$data );

        
// Prefill the needed data for Postmark.
        
$this->host           'smtp.postmarkapp.com';
        
$this->port           587;
        
$this->authentication 'yes';
        
$this->secure         'tls';
        
$this->name           'postmark';
        
// update the deliver method
        
$this->delivery_method 'api';
    }

    
/**
     * Processes the data for SMTP configuration.
     * Sets up the necessary credentials and settings for the Postmark connection.
     *
     * @param array $data The data array containing the email, name, and API key.
     *
     * @since 1.2.0
     *
     * @return void
     */
    
public function process_data( array $data ) {
        
$this->from_email $data['from_email'] ?? '';
        
$this->from_name  $data['from_name'] ?? '';
        
// this provider uses the API key for both username and password.
        
$this->smtp_username $data['smtp_username'] ?? '';
        
$this->smtp_password $data['smtp_username'] ?? '';
        
$this->description   'Postmark';
    }

    
/**
     * Sends an email using the Postmark API.
     *
     * @param array $email_data   {
     *                            Array of email data.
     *
     * @type array  $to           Required. Array of recipient email addresses.
     * @type array  $cc           Optional. Array of CC recipient email addresses.
     * @type array  $bcc          Optional. Array of BCC recipient email addresses.
     * @type array  $reply_to     Optional. Array of reply-to email addresses.
     * @type string $subject      Required. Email subject.
     * @type string $raw_body     Required. Email body content.
     * @type string $message_type Optional. Message type ('text/plain' or 'text/html').
     * @type array  $attachments  Optional. Array of attachments.
     *                            }
     * @since 2.1.3
     *
     * @return bool|WP_Error True on success, WP_Error on failure.
     */
    
public function send_use_api( array $email_data ) {
        if ( empty( 
$this->smtp_username ) ) {
            return new 
WP_Error'postmark_error''Missing Postmark API key' );
        }

        try {
            
// Format recipients
            
$to       $this->format_address_list$email_data['to'] );
            
$cc       = ! empty( $email_data['cc'] ) ? $this->format_address_list$email_data['cc'] ) : null;
            
$bcc      = ! empty( $email_data['bcc'] ) ? $this->format_address_list$email_data['bcc'] ) : null;
            
$reply_to = ! empty( $email_data['reply_to'] ) ? array_keys$email_data['reply_to'] )[0] : null;

            
// Format from address
            
$from $this->from_name ?
                
sprintf'%s <%s>'$this->from_name$this->from_email ) :
                
$this->from_email;

            
// Process attachments
            
$attachments = [];
            if ( ! empty( 
$email_data['attachments'] ) ) {
                foreach ( 
$email_data['attachments'] as $attachment ) {
                    
$attachment_file $attachment[0];
                    if ( 
file_exists$attachment_file ) ) {
                        
$file_content file_get_contents$attachment_file );
                        if ( 
$file_content !== false ) {
                            
$attachments[] = [
                                
'Name'        => basename$attachment_file ),
                                
'Content'     => base64_encode$file_content ),
                                
'ContentType' => mime_content_type$attachment_file ),
                            ];
                        }
                    }
                }
            }

            
// Prepare request body
            
$body = [
                
'From'          => $from,
                
'To'            => $to,
                
'Subject'       => $email_data['subject'],
                
'HtmlBody'      => $email_data['raw_body'],
                
'TextBody'      => wp_strip_all_tags$email_data['raw_body'] ),
                
'MessageStream' => 'outbound',
            ];

            
// if this is plain text then force to remove the HTML.
            
if ( $email_data['message_type'] === 'text/plain' ) {
                unset( 
$body['HtmlBody'] );
            }

            if ( 
$reply_to ) {
                
$body['ReplyTo'] = $reply_to;
            }
            if ( 
$cc ) {
                
$body['Cc'] = $cc;
            }
            if ( 
$bcc ) {
                
$body['Bcc'] = $bcc;
            }
            if ( ! empty( 
$attachments ) ) {
                
$body['Attachments'] = $attachments;
            }

            
// Make API request
            
$response wp_remote_post(
                
self::API_ENDPOINT,
                [
                    
'headers' => [
                        
'Accept'                  => 'application/json',
                        
'Content-Type'            => 'application/json',
                        
'X-Postmark-Server-Token' => $this->smtp_username,
                    ],
                    
'body'    => wp_json_encode$body ),
                    
// phpcs:ignore WordPressVIPMinimum.Performance.RemoteRequestTimeout.timeout_timeout
                    
'timeout' => 15// @TODO: can we decrease timeout?
                
]
            );

            if ( 
is_wp_error$response ) ) {
                return 
$response;
            }

            
$response_code wp_remote_retrieve_response_code$response );
            
$response_body wp_remote_retrieve_body$response );
            
$response_data json_decode$response_bodytrue );

            if ( 
$response_code !== 200 ) {
                
$error_message $response_data['Message'] ?? 'Unknown error occurred';

                return new 
WP_Error'postmark_api_error'$error_message );
            }

            return ! empty( 
$response_data['MessageID'] );

        } catch ( 
\Exception $e ) {
            return new 
WP_Error'postmark_error'$e->getMessage() );
        }
    }

    
/**
     * Formats an array of email addresses into a comma-separated string.
     *
     * @param array $addresses Array of email addresses. Each element can be either
     *                         a simple email address or an array containing email
     *                         and name.
     *
     * @since 2.1.3
     *
     * @return string Formatted string of email addresses.
     */
    
private function format_address_list( array $addresses ): string {
        return 
implode(
            
',',
            
array_map(
                function ( 
$address ) {
                    return ! empty( 
$address[1] ) ?
                    
sprintf'%s <%s>'$address[1], $address[0] ) :
                    
$address[0];
                },
                
$addresses 
            

        );
    }
}