PluginProbe
Fluent Support – Helpdesk & Customer Support Ticket System / 2.4.5
Fluent Support – Helpdesk & Customer Support Ticket System v2.4.5
2.4.5 2.4.0 2.3.2 2.3.1 2.3.0 2.2.1 2.2.0 trunk 1.10.0 1.10.1 1.10.2 1.10.3 1.10.4 1.10.5 1.4.0 1.4.1 1.4.2 1.4.5 1.4.6 1.4.7 1.5.0 1.5.1 1.5.2 1.5.3 1.5.4 All 69 releases
← All changes | app/Hooks/Handlers/EmailNotificationHandler.php +349 -27 1.4.1 → 2.4.5 View file →
@@ -2,11 +2,16 @@
2 2
3 3 namespace FluentSupport\App\Hooks\Handlers;
4 4
5 5 use FluentSupport\App\App;
6 +use FluentSupport\App\Models\Agent;
7 +use FluentSupport\App\Models\Meta;
8 +use FluentSupport\App\Models\Ticket;
6 9 use FluentSupport\App\Services\EmailNotification\Settings;
7 10 use FluentSupport\App\Services\Emogrifier;
11 +use FluentSupport\App\Services\Helper;
8 12 use FluentSupport\App\Services\Mailer;
13 +use FluentSupport\App\Services\Tickets\AgentTicketAccess;
9 14 use FluentSupport\Framework\Support\Arr;
10 15
11 16 class EmailNotificationHandler
12 17 {
@@ -19,10 +24,12 @@
19 24 }
20 25
21 26 // Let's send welcome email to customer if enabled
22 27 $emailSettings = (new Settings())->getBoxEmailSettings($mailbox, 'ticket_created_email_to_customer');
23 - if ($customer->status == 'inactive' && $emailSettings && $emailSettings['status'] == 'yes') {
24 28
29 + // Blocked customers get no email; the admin copy below still goes out.
30 + if ($customer && $customer->canReceiveNotifications()
31 + && $this->shouldSendEmail($emailSettings, 'ticket_created_email_to_customer', $ticket, $customer)) {
25 32 $subject = apply_filters('fluent_support/parse_smartcode_data', $emailSettings['email_subject'], [
26 33 'customer' => $customer,
27 34 'business' => $mailbox,
28 35 'ticket' => $ticket
@@ -27,8 +34,10 @@
27 34 'business' => $mailbox,
28 35 'ticket' => $ticket
29 36 ]);
30 37
38 + $subject = apply_filters('fluent_support/ticket_email_subject', $subject, $ticket, 'ticket_created_email_to_customer');
39 +
31 40 $emailBody = $this->parseEmailBody($emailSettings['email_body'], [
32 41 'customer' => $customer,
33 42 'business' => $mailbox,
34 43 'ticket' => $ticket,
@@ -34,21 +43,43 @@
34 43 'ticket' => $ticket,
35 44 'email_type' => 'ticket_created_email_to_customer'
36 45 ]);
37 46
38 - $headers = $mailbox->getMailerHeader();
39 - if ($ticket->message_id) {
40 - // $headers[] = 'Message-ID: ' . $ticket->message_id;
47 + $headers = self::automatedHeaders($mailbox->getMailerHeader());
48 +
49 + $headers = apply_filters('fluent_support/mail_to_customer_header', $headers, [
50 + 'cc_email' => $ticket->getSettingsValue('cc_email', []),
51 + 'hook_type' => 'ticket_created_email_to_customer',
52 + 'ticket' => $ticket
53 + ]);
54 +
55 + $attachments = [];
56 +
57 + if ($emailSettings['send_attachments'] == 'yes' && ($files = $ticket->attachments)) {
58 + foreach ($files as $file) {
59 + if ($file->driver == 'local') {
60 + $filePath = $file->file_path;
61 + } else {
62 + $filePath = Arr::get($file->settings, 'local_temp_path');
63 + }
64 + if (file_exists($filePath)) {
65 + $attachments[] = $filePath;
66 + }
67 + }
41 68 }
42 - Mailer::send($customer->email, $subject, $emailBody, $headers);
69 +
70 + Mailer::send($customer->email, $subject, $emailBody, $headers, $attachments);
43 71 }
44 72
45 73 // let's send email to admin if enabled
46 74 $emailSettings = (new Settings())->getBoxEmailSettings($mailbox, 'ticket_created_email_to_admin');
47 - if ($emailSettings && $emailSettings['status'] == 'yes' && is_email($mailbox->settings['admin_email_address'])) {
75 + if ($this->shouldSendEmail($emailSettings, 'ticket_created_email_to_admin', $ticket, $customer)
76 + && is_email($mailbox->settings['admin_email_address'])
77 + ) {
48 78
49 79 $mailTo = Arr::get($mailbox->settings, 'admin_email_address');
50 - if(!$mailTo || !is_email($mailTo)) {
80 +
81 + if (!$mailTo || !is_email($mailTo)) {
51 82 return;
52 83 }
53 84
54 85 $subject = apply_filters('fluent_support/parse_smartcode_data', $emailSettings['email_subject'], [
@@ -56,8 +87,10 @@
56 87 'business' => $mailbox,
57 88 'ticket' => $ticket
58 89 ]);
59 90
91 + $subject = apply_filters('fluent_support/ticket_email_subject', $subject, $ticket, 'ticket_created_email_to_admin');
92 +
60 93 $emailBody = $this->parseEmailBody($emailSettings['email_body'], [
61 94 'customer' => $customer,
62 95 'business' => $mailbox,
63 96 'ticket' => $ticket,
@@ -63,15 +96,29 @@
63 96 'ticket' => $ticket,
64 97 'email_type' => 'ticket_created_email_to_admin'
65 98 ]);
66 99
67 - $headers = $mailbox->getMailerHeader();
68 - if ($ticket->message_id) {
69 - // $headers[] = 'Message-ID: ' . $ticket->message_id;
100 + $headers = self::automatedHeaders($mailbox->getMailerHeader());
101 +
102 + $attachments = [];
103 +
104 + if ($emailSettings['send_attachments'] == 'yes' && ($files = $ticket->attachments)) {
105 + foreach ($files as $file) {
106 +
107 + if ($file->driver == 'local') {
108 + $filePath = $file->file_path;
109 + } else {
110 + $filePath = Arr::get($file->settings, 'local_temp_path');
111 + }
112 + if (file_exists($filePath)) {
113 + $attachments[] = $filePath;
114 + }
115 +
116 + }
70 117 }
71 - Mailer::send($mailTo, $subject, $emailBody, $headers);
118 +
119 + Mailer::send($mailTo, $subject, $emailBody, $headers, $attachments);
72 120 }
73 -
74 121 }
75 122
76 123 public function agentReplied($response, $ticket, $agent)
77 124 {
@@ -90,12 +137,16 @@
90 137
91 138 $ticket->load('customer');
92 139 $customer = $ticket->customer;
93 140
94 - if($customer->status == 'inactive') {
141 + if (!$customer->canReceiveNotifications()) {
95 142 return false;
96 143 }
97 144
145 + if (!$this->shouldSendEmail($emailSettings, 'ticket_replied_by_agent_email_to_customer', $ticket, $customer)) {
146 + return false;
147 + }
148 +
98 149 $subject = apply_filters('fluent_support/parse_smartcode_data', $emailSettings['email_subject'], [
99 150 'customer' => $customer,
100 151 'business' => $mailbox,
101 152 'ticket' => $ticket,
@@ -102,8 +153,10 @@
102 153 'response' => $response,
103 154 'agent' => $agent
104 155 ]);
105 156
157 + $subject = apply_filters('fluent_support/ticket_email_subject', $subject, $ticket, 'ticket_replied_by_agent_email_to_customer');
158 +
106 159 $emailBody = $this->parseEmailBody($emailSettings['email_body'], [
107 160 'customer' => $customer,
108 161 'business' => $mailbox,
109 162 'ticket' => $ticket,
@@ -112,11 +165,31 @@
112 165 'email_type' => 'ticket_replied_by_agent_email_to_customer'
113 166 ]);
114 167
115 168
116 - $headers = $mailbox->getMailerHeader();
169 + // Written by the agent, so the From name follows the inbox's From name setting.
170 + $headers = $mailbox->getMailerHeader($agent);
171 + $headers = apply_filters('fluent_support/mail_to_customer_header', $headers, [
172 + 'cc_email' => $response->getSettingsValue('cc_email', []),
173 + 'hook_type' => 'ticket_replied_by_agent_email_to_customer',
174 + 'ticket' => $ticket
175 + ]);
176 + $attachments = [];
117 177
118 - Mailer::send($customer->email, $subject, $emailBody, $headers);
178 + if ($emailSettings['send_attachments'] == 'yes' && ($files = $response->attachments)) {
179 + foreach ($files as $file) {
180 + if ($file->driver == 'local') {
181 + $filePath = $file->file_path;
182 + } else {
183 + $filePath = Arr::get($file->settings, 'local_temp_path');
184 + }
185 + if (file_exists($filePath)) {
186 + $attachments[] = $filePath;
187 + }
188 + }
189 + }
190 +
191 + Mailer::send($customer->email, $subject, $emailBody, $headers, $attachments);
119 192 }
120 193 }
121 194
122 195 public function closedByAgent($ticket, $agent)
@@ -132,12 +205,15 @@
132 205
133 206 $ticket->load('customer');
134 207 $customer = $ticket->customer;
135 208
136 - if($customer->status == 'inactive') {
209 + if (!$customer->canReceiveNotifications()) {
137 210 return false;
138 211 }
139 212
213 + if (!$this->shouldSendEmail($emailSettings, 'ticket_closed_by_agent_email_to_customer', $ticket, $customer)) {
214 + return false;
215 + }
140 216
141 217 $subject = apply_filters('fluent_support/parse_smartcode_data', $emailSettings['email_subject'], [
142 218 'customer' => $customer,
143 219 'business' => $mailbox,
@@ -144,8 +220,10 @@
144 220 'ticket' => $ticket,
145 221 'agent' => $agent,
146 222 ]);
147 223
224 + $subject = apply_filters('fluent_support/ticket_email_subject', $subject, $ticket, 'ticket_closed_by_agent_email_to_customer');
225 +
148 226 $emailBody = $this->parseEmailBody($emailSettings['email_body'], [
149 227 'customer' => $customer,
150 228 'business' => $mailbox,
151 229 'ticket' => $ticket,
@@ -152,12 +230,14 @@
152 230 'agent' => $agent,
153 231 'email_type' => 'ticket_closed_by_agent_email_to_customer'
154 232 ]);
155 233
156 - $headers = $mailbox->getMailerHeader();
157 - if ($ticket->message_id) {
158 - // $headers[] = 'Message-ID: ' . $ticket->message_id;
159 - }
234 + $headers = self::automatedHeaders($mailbox->getMailerHeader());
235 + $headers = apply_filters('fluent_support/mail_to_customer_header', $headers, [
236 + 'cc_email' => $ticket->getSettingsValue('cc_email', []),
237 + 'hook_type' => 'ticket_closed_by_agent_email_to_customer',
238 + 'ticket' => $ticket
239 + ]);
160 240 Mailer::send($customer->email, $subject, $emailBody, $headers);
161 241 }
162 242 }
163 243
@@ -169,19 +249,19 @@
169 249 }
170 250
171 251 // Let's send welcome email to customer if enabled
172 252 $emailSettings = (new Settings())->getBoxEmailSettings($mailbox, 'ticket_replied_by_customer_email_to_admin');
173 - if ($emailSettings && $emailSettings['status'] == 'yes') {
253 + if ($this->shouldSendEmail($emailSettings, 'ticket_replied_by_customer_email_to_admin', $ticket, $customer)) {
174 254
175 255 $ticket->load('agent');
176 256 $agent = $ticket->agent;
177 257
178 258 $emailTo = $mailbox->settings['admin_email_address'];
179 - if($agent) {
259 + if ($agent) {
180 260 $emailTo = $agent->email;
181 261 }
182 262
183 - if(!$emailTo || !is_email($emailTo)) {
263 + if (!$emailTo || !is_email($emailTo)) {
184 264 return;
185 265 }
186 266
187 267 $subject = apply_filters('fluent_support/parse_smartcode_data', $emailSettings['email_subject'], [
@@ -191,8 +271,10 @@
191 271 'response' => $response,
192 272 'agent' => $agent
193 273 ]);
194 274
275 + $subject = apply_filters('fluent_support/ticket_email_subject', $subject, $ticket, 'ticket_replied_by_customer_email_to_admin');
276 +
195 277 $emailBody = $this->parseEmailBody($emailSettings['email_body'], [
196 278 'customer' => $customer,
197 279 'business' => $mailbox,
198 280 'ticket' => $ticket,
@@ -200,17 +282,209 @@
200 282 'agent' => $agent,
201 283 'email_type' => 'ticket_replied_by_customer_email_to_admin'
202 284 ]);
203 285
204 - $headers = $mailbox->getMailerHeader();
205 - if ($ticket->message_id) {
206 - // $headers[] = 'Message-ID: ' . $ticket->message_id;
286 + $headers = self::automatedHeaders($mailbox->getMailerHeader());
287 + $attachments = [];
288 +
289 + if ($emailSettings['send_attachments'] == 'yes' && ($files = $response->attachments)) {
290 + foreach ($files as $file) {
291 + if ($file->driver == 'local') {
292 + $filePath = $file->file_path;
293 + } else {
294 + $filePath = Arr::get($file->settings, 'local_temp_path');
295 + }
296 + if (file_exists($filePath)) {
297 + $attachments[] = $filePath;
298 + }
299 + }
207 300 }
208 301
302 + Mailer::send($emailTo, $subject, $emailBody, $headers, $attachments);
303 + }
304 + }
305 +
306 + public function onAgentAssign(Agent $agent, Ticket $ticket, ?Agent $assigner = null)
307 + {
308 + if ($agent->status !== 'active' || (int) $ticket->agent_id !== (int) $agent->id) {
309 + return;
310 + }
311 +
312 + if (!(new AgentTicketAccess())->canAccess($agent, $ticket)) {
313 + return;
314 + }
315 +
316 + $currentUser = Helper::getAgentByUserId();
317 +
318 + if ($currentUser && $currentUser->user_id == $agent->user_id) {
319 + return;
320 + }
321 +
322 + $mailbox = $ticket->mailbox;
323 +
324 + if (!$mailbox) {
325 + return;
326 + }
327 +
328 + // Let's send notification email to agent if enabled
329 + $emailSettings = (new Settings())->getBoxEmailSettings($mailbox, 'ticket_agent_on_change');
330 +
331 + if ($this->shouldSendEmail($emailSettings, 'ticket_agent_on_change', $ticket, $agent)) {
332 +
333 + if ($agent) {
334 + $emailTo = $agent->email;
335 + }
336 +
337 + if (!$emailTo || !is_email($emailTo)) {
338 + return;
339 + }
340 +
341 + $subject = apply_filters('fluent_support/parse_smartcode_data', $emailSettings['email_subject'], [
342 + 'business' => $mailbox,
343 + 'ticket' => $ticket,
344 + 'agent' => $agent,
345 + 'assigner' => $assigner
346 + ]);
347 +
348 + $subject = apply_filters('fluent_support/ticket_email_subject', $subject, $ticket, 'ticket_agent_on_change');
349 +
350 + $emailBody = $this->parseEmailBody($emailSettings['email_body'], [
351 + 'business' => $mailbox,
352 + 'ticket' => $ticket,
353 + 'agent' => $agent,
354 + 'assigner' => $assigner,
355 + 'email_type' => 'ticket_agent_on_change'
356 + ]);
357 +
358 + $headers = self::automatedHeaders($mailbox->getMailerHeader());
359 +
209 360 Mailer::send($emailTo, $subject, $emailBody, $headers);
210 361 }
211 362 }
212 363
364 + public function ticketCreatedByAgent($ticket, $customer, $agent)
365 + {
366 + $mailbox = $ticket->mailbox;
367 +
368 + if (!$mailbox || !$customer || !$customer->canReceiveNotifications()) {
369 + return;
370 + }
371 +
372 + // Let's send welcome email to customer if enabled
373 + $emailSettings = (new Settings())->getBoxEmailSettings($mailbox, 'ticket_created_by_agent_email_to_customer');
374 + if ($this->shouldSendEmail($emailSettings, 'ticket_created_by_agent_email_to_customer', $ticket, $customer)) {
375 + $subject = apply_filters('fluent_support/parse_smartcode_data', $emailSettings['email_subject'], [
376 + 'customer' => $customer,
377 + 'agent' => $agent,
378 + 'business' => $mailbox,
379 + 'ticket' => $ticket
380 + ]);
381 +
382 + $subject = apply_filters('fluent_support/ticket_email_subject', $subject, $ticket, 'ticket_created_by_agent_email_to_customer');
383 +
384 + $emailBody = $this->parseEmailBody($emailSettings['email_body'], [
385 + 'customer' => $customer,
386 + 'business' => $mailbox,
387 + 'agent' => $agent,
388 + 'ticket' => $ticket,
389 + 'email_type' => 'ticket_created_by_agent_email_to_customer'
390 + ]);
391 +
392 + $headers = apply_filters('fluent_support/mail_to_customer_header', self::automatedHeaders($mailbox->getMailerHeader()), [
393 + 'hook_type' => 'ticket_created_by_agent_email_to_customer',
394 + 'cc_email' => [],
395 + 'ticket' => $ticket
396 + ]);
397 +
398 + $attachments = [];
399 +
400 + if ($emailSettings['send_attachments'] == 'yes' && ($files = $ticket->attachments)) {
401 + foreach ($files as $file) {
402 + if ($file->driver == 'local') {
403 + $filePath = $file->file_path;
404 + } else {
405 + $filePath = Arr::get($file->settings, 'local_temp_path');
406 + }
407 + if (file_exists($filePath)) {
408 + $attachments[] = $filePath;
409 + }
410 + }
411 + }
412 +
413 + Mailer::send($customer->email, $subject, $emailBody, $headers, $attachments);
414 + }
415 + }
416 +
417 + public function ticketCreatedByAgentOnBehalf($response, $ticket, $agent)
418 + {
419 + $mailbox = $ticket->mailbox;
420 +
421 + if (!$mailbox) {
422 + return;
423 + }
424 +
425 + $emailSettings = (new Settings())->getBoxEmailSettings($mailbox, 'ticket_created_by_agent_on_behalf_email_to_customer');
426 + if ($this->shouldSendEmail($emailSettings, 'ticket_created_by_agent_on_behalf_email_to_customer', $ticket)) {
427 +
428 + $ticket->load('customer');
429 + $customer = $ticket->customer;
430 +
431 + if (!$customer->canReceiveNotifications()) {
432 + return false;
433 + }
434 +
435 + $subject = apply_filters('fluent_support/parse_smartcode_data', $emailSettings['email_subject'], [
436 + 'customer' => $customer,
437 + 'agent' => $agent,
438 + 'business' => $mailbox,
439 + 'ticket' => $ticket,
440 + 'response' => $response
441 + ]);
442 +
443 + $subject = apply_filters('fluent_support/ticket_email_subject', $subject, $ticket, 'ticket_created_by_agent_on_behalf_email_to_customer');
444 +
445 + $emailBody = $this->parseEmailBody($emailSettings['email_body'], [
446 + 'customer' => $customer,
447 + 'business' => $mailbox,
448 + 'agent' => $agent,
449 + 'ticket' => $ticket,
450 + 'response' => $response,
451 + 'email_type' => 'ticket_created_by_agent_on_behalf_email_to_customer'
452 + ]);
453 +
454 + $headers = apply_filters('fluent_support/mail_to_customer_header', $mailbox->getMailerHeader($agent), [
455 + 'hook_type' => 'ticket_created_by_agent_on_behalf_email_to_customer',
456 + 'cc_email' => [],
457 + 'ticket' => $ticket
458 + ]);
459 +
460 + $attachments = [];
461 +
462 + if ($emailSettings['send_attachments'] == 'yes') {
463 + $files = $response->attachments;
464 +
465 + // Agent-initiated ticket uploads are stored on the ticket, while this email
466 + // is rendered from the synthetic first response created during ticket creation.
467 + if ((!$files || $files->isEmpty()) && $ticket->attachments) {
468 + $files = $ticket->attachments;
469 + }
470 +
471 + foreach ($files as $file) {
472 + if ($file->driver == 'local') {
473 + $filePath = $file->file_path;
474 + } else {
475 + $filePath = Arr::get($file->settings, 'local_temp_path');
476 + }
477 + if (file_exists($filePath)) {
478 + $attachments[] = $filePath;
479 + }
480 + }
481 + }
482 +
483 + Mailer::send($customer->email, $subject, $emailBody, $headers, $attachments);
484 + }
485 + }
486 +
213 487 private function emailTemplateCss()
214 488 {
215 489 $app = App::getInstance();
216 490 return $app->view->make('emails.styles');
@@ -227,15 +501,63 @@
227 501 } else {
228 502 $businessName = get_bloginfo('name');
229 503 }
230 504
231 - $footerText = apply_filters('fluent_support/email_footer_credit', 'This email is a service from ' . $businessName . '. Support Plugin is Powered by <a href="https://fluentsupport.com/?utm_source=user&utm_medium=wp&utm_campaign=mail_footer" style="color:#9e9e9e;" target="_new">FluentSupport</a>.');
505 + $footerCreditUrl = Helper::getUpgradeUrl('mail_footer', ['base_url' => 'https://fluentsupport.com/']);
506 + $footerText = apply_filters('fluent_support/email_footer_credit', 'This email is a service from ' . $businessName . '. Support Plugin is Powered by <a href="' . esc_url($footerCreditUrl) . '" style="color:#9e9e9e;" target="_new">FluentSupport</a>.');
232 507
233 508 $data['email_footer'] = $footerText;
234 509
510 + $emailTypeForCustomerFooter = ['ticket_created_email_to_customer', 'ticket_replied_by_agent_email_to_customer', 'ticket_closed_by_agent_email_to_customer', 'ticket_created_by_agent_on_behalf_email_to_customer'];
511 +
512 + if (defined('FLUENTSUPPORTPRO') && in_array($data['email_type'], $emailTypeForCustomerFooter)
513 + && !is_null($data['business']->email_footer)) {
514 + $data['email_footer'] = apply_filters('fluent_support/parse_smartcode_data', $data['business']->email_footer, $data);
515 + }
516 +
235 517 $emailBody = $app->view->make('emails.ticket_template', $data);
236 518 $emogrifier = new Emogrifier($emailBody, $this->emailTemplateCss());
237 519 $emogrifier->disableInvisibleNodeRemoval();
238 520 return $emogrifier->emogrify();
521 + }
522 +
523 + protected function shouldSendEmail($emailSettings, $emailType, $ticket, $person = null)
524 + {
525 + if (!$emailSettings || $emailSettings['status'] != 'yes') {
526 + return false;
527 + }
528 +
529 + return apply_filters('fluent_support/should_send_notification', true, 'email', $emailType, $ticket, $person);
530 + }
531 +
532 + /**
533 + * Mark a system-generated email (confirmations, closed notices, agent alerts) so
534 + * autoresponders don't answer it (RFC 3834 Auto-Submitted, and Outlook's
535 + * X-Auto-Response-Suppress). An answer would come back through email piping and
536 + * could start a mail loop. Replies an agent writes are not marked.
537 + *
538 + * @param array $headers
539 + * @return array
540 + */
541 + public static function automatedHeaders($headers)
542 + {
543 + if (!apply_filters('fluent_support/mark_automated_emails', true)) {
544 + return $headers;
545 + }
546 +
547 + $headers[] = 'Auto-Submitted: auto-generated';
548 + $headers[] = 'X-Auto-Response-Suppress: All';
549 +
550 + return $headers;
551 + }
552 +
553 + public function getMailerHeaderWithCc($headers, $info)
554 + {
555 + if (isset($info['cc_email'])) {
556 + $CcHeaders = !empty($info['cc_email']) && is_array($info['cc_email']) ? implode(', ', $info['cc_email']) : '';
557 + $headers[] = $CcHeaders ? "Cc: $CcHeaders" : '';
558 + }
559 +
560 + return $headers;
239 561 }
240 562
241 563 }