Jump to content

Ticket attachments in staff email notifications


vikingo

Recommended Posts

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!

Link to comment
Share on other sites

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.

Link to comment
Share on other sites

Join the conversation

You can post now and register later. If you have an account, sign in now to post with your account.

Guest
Reply to this topic...

×   Pasted as rich text.   Paste as plain text instead

  Only 75 emoji are allowed.

×   Your link has been automatically embedded.   Display as a link instead

×   Your previous content has been restored.   Clear editor

×   You cannot paste images directly. Upload or insert images from URL.

  • Recently Browsing   0 members

    • No registered users viewing this page.
×
×
  • Create New...

Important Information

By using this site, you agree to our Terms of Use & Guidelines and understand your posts will initially be pre-moderated