vikingo Posted 23 hours ago Share Posted 23 hours ago Hello everyone, When a client opens or replies to a support ticket with attached files, the staff email notification lists the attachments in the message body, but the physical files are not attached to the email itself. Is there any native setting or option in WHMCS to include the actual file attachments in staff ticket notifications? Alternatively, does anyone have a working hook or snippet that accomplishes this? Thank you in advance for your help! 0 Quote Link to comment Share on other sites More sharing options...
K n K Web Services Posted 8 hours ago Share Posted 8 hours ago No, there's no native setting for this. WHMCS's own docs "ticket attachments are automatically included in the notification email sent to the client, but explicitly not forwarded to staff in ticket notification emails. That's by design, not a bug or misconfiguration on your end." Working fix — EmailPreSend hook: This uses the EmailPreSend hook, which lets you inject file attachments into any outgoing email by returning an attachments array. Rather than reaching into the filesystem/DB directly (which breaks if you're on S3 or another external storage backend), it pulls the files through WHMCS's own GetTicket and GetTicketAttachment API actions, so it stays storage-agnostic: <?php add_hook('EmailPreSend', 1, function ($vars) { // Only touch ticket-related notification templates if (stripos($vars['messagename'], 'Support Ticket') === false) { return []; } $ticketId = $vars['relid']; if (!$ticketId) { return []; } $ticket = localAPI('GetTicket', ['ticketid' => $ticketId]); if ($ticket['result'] !== 'success') { return []; } $attachmentsOut = []; $pullAttachment = function ($replyId, $index) use ($ticketId) { $file = localAPI('GetTicketAttachment', [ 'ticketid' => $ticketId, 'replyid' => $replyId, 'index' => $index, ]); return $file['result'] === 'success' ? $file : null; }; // Original ticket message attachments (replyid 0) if (!empty($ticket['attachments']['attachment'])) { foreach ((array) $ticket['attachments']['attachment'] as $i => $att) { if ($file = $pullAttachment(0, $i)) { $attachmentsOut[] = [ 'filename' => $file['filename'], 'data' => base64_decode($file['data']), ]; } } } // Latest reply's attachments (covers reply notifications) if (!empty($ticket['replies']['reply'])) { $lastReply = end($ticket['replies']['reply']); if (!empty($lastReply['attachments'])) { foreach ($lastReply['attachments'] as $att) { if ($file = $pullAttachment($lastReply['replyid'], $att['index'])) { $attachmentsOut[] = [ 'filename' => $file['filename'], 'data' => base64_decode($file['data']), ]; } } } } return $attachmentsOut ? ['attachments' => $attachmentsOut] : []; }); Drop that in includes/hooks/. A couple of notes: The stripos($vars['messagename'], 'Support Ticket') filter is deliberately broad since the exact unique name for your staff-facing notification template can vary (custom departments, renamed templates, etc). If you want to scope it tighter, temporarily add logActivity($vars['messagename']); inside the hook, trigger a test ticket, and check Configuration > System Logs > Activity Log to see the exact name being fired — then swap the stripos check for an exact match. This will also fire for the client-facing "Support Ticket Reply" template, but since clients already get their own attachments natively, this is redundant, not harmful — just a marginal size bump. If that bothers you, add a check against $vars['to'] matching your admin email domain, but that's fragile if staff use personal addresses. Tested logic is based on the documented GetTicket/GetTicketAttachment API responses (attachment index + base64 data) — should hold across supported WHMCS versions since it doesn't touch internal table structure directly. 0 Quote Link to comment Share on other sites More sharing options...
Recommended Posts
Join the conversation
You can post now and register later. If you have an account, sign in now to post with your account.