Infos:
- Zammad version: 6.5.1
- Installation type: Docker Compose
- Operating system: Ubuntu
- Browser: Latest version of Safari
Expected behavior:
- After creating a ticket, the customer should receive a confirmation email.
Actual behavior:
- I filled out the ticket form and successfully submitted it.
- The system received the ticket and correctly forwards the ticket to the agent, but no notification email is sent to the customer.
- I have double-checked the email configuration, customer settings, and triggers, but the system still does not send emails to the customer.
- The form was customize by me and here is the function:
add_action(‘rest_api_init’, function () {
register_rest_route(‘support/v1’, ‘/ticket’, array(
‘methods’ => ‘POST’,
‘callback’ => ‘handle_support_ticket’,
‘permission_callback’ => ‘__return_true’,
));
});
function handle_support_ticket(WP_REST_Request $request) {
$p = $request->get_body_params();
$files = $request->get_file_params();
$firstname = sanitize_text_field($p['firstname'] ?? '');
$lastname = sanitize_text_field($p['lastname'] ?? '');
$email = sanitize_email($p['email'] ?? '');
$phone = sanitize_text_field($p['phone'] ?? '');
$department = sanitize_text_field($p['department'] ?? '');
$tax_code = sanitize_text_field($p['tax_code'] ?? '');
$body = sanitize_textarea_field($p['body'] ?? '');
$group_id = intval($p['group_id'] ?? 0);
$product_type = sanitize_text_field($p['product_type'] ?? '');
$product_code = sanitize_text_field($p['product_code'] ?? '');
$product_name = sanitize_text_field($p['product_name'] ?? '');
if (empty($email) || !is_email($email)) {
return new WP_Error('bad_request', 'Địa chỉ email không hợp lệ.', ['status' => 400]);
}
if (empty($firstname) || empty($lastname) || empty($body) || empty($group_id)) {
return new WP_Error('bad_request', 'Vui lòng điền đầy đủ các trường bắt buộc.', ['status' => 400]);
}
if (($group_id === 7 || $group_id === 11) && (empty($product_code) || empty($product_name))) {
return new WP_Error('bad_request', 'Vui lòng nhập Mã và Tên sản phẩm cho yêu cầu Hỗ trợ kỹ thuật/Bảo hành.', ['status' => 400]);
}
if ($group_id === 8 && empty($product_type)) {
return new WP_Error('bad_request', 'Vui lòng chọn Loại sản phẩm cho yêu cầu Báo giá.', ['status' => 400]);
}
if ($group_id === 8 && !empty($product_type)) {
if ($product_type === '9') $group_id = 9;
if ($product_type === '10') $group_id = 10;
}
$body_details = "";
if ($product_code || $product_name) {
$body_details .= "\n\n--- Thông tin sản phẩm ---\n";
if ($product_code) $body_details .= "Mã sản phẩm: {$product_code}\n";
if ($product_name) $body_details .= "Tên sản phẩm: {$product_name}\n";
}
if ($tax_code) $body_details .= "\nMã số thuế: {$tax_code}";
if ($department) $body_details .= "\nĐơn vị/Tổ chức: {$department}";
if ($phone) $body_details .= "\nSĐT: {$phone}";
$final_body = $body . $body_details;
$api_url = "https://{my web adress}/api/v1";
$api_token = "{My Token}";
$ch = curl_init("$api_url/users/search?query=" . urlencode($email));
curl_setopt_array($ch, [ CURLOPT_HTTPHEADER => ["Authorization: Token token=$api_token", "Content-Type: application/json"], CURLOPT_RETURNTRANSFER => true, CURLOPT_TIMEOUT => 20 ]);
$user_response = curl_exec($ch);
if (curl_errno($ch)) { error_log("Zammad user search curl error: " . curl_error($ch)); /* ... handle error ... */ }
curl_close($ch);
$user = json_decode($user_response, true);
$customer_id = (!empty($user) && isset($user[0]['id'])) ? $user[0]['id'] : null;
if (!$customer_id) {
$new_user_data = [ "firstname" => $firstname, "lastname" => $lastname ?: "-", "email" => $email, "phone" => $phone, "department" => $department, "roles" => ["Customer"] ];
$ch = curl_init("$api_url/users");
curl_setopt_array($ch, [ CURLOPT_HTTPHEADER => ["Authorization: Token token=$api_token", "Content-Type: application/json"], CURLOPT_RETURNTRANSFER => true, CURLOPT_POST => true, CURLOPT_POSTFIELDS => json_encode($new_user_data), CURLOPT_TIMEOUT => 20 ]);
$create_user_response = curl_exec($ch);
if (curl_errno($ch)) { error_log("Zammad create user curl error: " . curl_error($ch)); /* ... handle error ... */ }
curl_close($ch);
$new_user = json_decode($create_user_response, true);
if (!empty($new_user['id'])) {
$customer_id = $new_user['id'];
} else {
error_log("Zammad create user FAILED: " . $create_user_response);
return new WP_Error('user_creation_failed', 'Không thể tạo user trên hệ thống hỗ trợ.', ['status' => 500, 'details' => json_decode($create_user_response)]);
}
}
$attachment_ids = [];
if (!empty($files['attachments'])) {
$attachments = [];
if (is_array($files['attachments']['name'])) {
$attachments = $files['attachments'];
} else {
foreach ($files['attachments'] as $key => $value) { $attachments[$key] = [$value]; }
}
foreach ($attachments['tmp_name'] as $i => $tmp_name) {
if ($attachments['error'][$i] === UPLOAD_ERR_OK) {
$file_path = $tmp_name;
$file_name = $attachments['name'][$i];
$mime = mime_content_type($file_path) ?: 'application/octet-stream';
$ch = curl_init("$api_url/upload");
curl_setopt_array($ch, [ CURLOPT_HTTPHEADER => ["Authorization: Token token=$api_token"], CURLOPT_RETURNTRANSFER => true, CURLOPT_POST => true, CURLOPT_POSTFIELDS => ['file' => new CURLFile($file_path, $mime, $file_name)], CURLOPT_TIMEOUT => 60 ]);
$upload_response = curl_exec($ch);
if (curl_errno($ch)) { error_log("Zammad upload curl error for {$file_name}: " . curl_error($ch)); }
curl_close($ch);
$upload_json = json_decode($upload_response, true);
if (!empty($upload_json['id'])) {
$attachment_ids[] = $upload_json['id'];
} else {
error_log("Zammad upload FAILED for file {$file_name}: " . $upload_response);
}
}
}
}
$ticket_data = [
"title" => "Yêu cầu hỗ trợ từ $firstname $lastname",
"group_id" => $group_id,
"customer_id" => $customer_id,
"article" => [ "subject" => "Hỗ trợ từ $firstname $lastname", "body" => $final_body, "type" => "note", "internal" => false, "attachments" => $attachment_ids ],
];
$ch = curl_init("$api_url/tickets");
curl_setopt_array($ch, [ CURLOPT_HTTPHEADER => ["Authorization: Token token=$api_token", "Content-Type: application/json"], CURLOPT_RETURNTRANSFER => true, CURLOPT_POST => true, CURLOPT_POSTFIELDS => json_encode($ticket_data), CURLOPT_TIMEOUT => 30 ]);
$response = curl_exec($ch);
if (curl_errno($ch)) { error_log("Zammad ticket curl error: " . curl_error($ch)); /* ... handle error ... */ }
curl_close($ch);
error_log("Zammad ticket request: " . json_encode($ticket_data));
error_log("Zammad ticket response: " . $response);
$result = json_decode($response, true);
if (!empty($result['id'])) {
// Trả về cả success và ticket number để JS sử dụng
return new WP_REST_Response(['success' => true, 'ticket' => $result['number']], 200);
}
$msg = $result['error'] ?? 'Không thể tạo ticket. Vui lòng thử lại.';
return new WP_Error('ticket_creation_failed', $msg, ['status' => 500, 'details' => $result]);
}
I used the default trigger:


