wp_mail attachment not working in wordpress

You don’t need to know the file names before, you’ll have access to them.

I saw you using $subject = $_POST['subject']; – this means the subject will be the value of the input with the name of “subject”. In your case, this one :

<input id="subject" class="form-control" name="subject" type="text" /></div>

We can use the same logic to get the files, but instead of $_POST, we’ll look in $_FILES. Your file form has the name of “image”, so the location will be $_FILES[‘image’]. We can then handle the upload.
I wrote a small example to show you how you would do that, but you should add some validation on it, depending on your use case :

if(isset($_POST['submit']) && strpos($_SERVER['HTTP_REFERER'], 'https://example.com/custom-file/') !== false) {
    $to = '[email protected]'; // Replace with your own email address
    $subject = $_POST['subject']; // Get the value of the subject field from the form
    $message = "Name: " . $_POST['name'] . "<br><br>";
    $message .= "Email: " . $_POST['email'] . "<br><br>";
    $message .= "Message: " . $_POST['message'] . "<br><br>";

    $headers = array('Content-Type: text/html; charset=UTF-8');

    // Handle the uploaded file
    if ($_FILES['image']['error'] == UPLOAD_ERR_OK) {
        $tmp_name = $_FILES['image']['tmp_name'];
        $filename = basename($_FILES['image']['name']);
        $upload_dir = wp_upload_dir();
        $destination = $upload_dir['basedir'] . "https://wordpress.stackexchange.com/" . $filename;

        // Move the file to the uploads directory
        if (move_uploaded_file($tmp_name, $destination)) {
            $attachments = array($destination);
        }
    }

    if (wp_mail($to, $subject, $message, $headers, $attachments)) {
        wp_redirect('/thank-you-contact-form-sent'); // Replace with the URL of your thank-you page
        exit();
    } else {
        wp_redirect('/sorry-contact-form-not-sent'); // Replace with the URL of your sorry page
        exit();
    }
}

EDIT

If you want to send the files as attachments, you can use the $attachments parameter for wp_mail(), like so :

wp_mail($to, $subject, $message, $headers, $attachments)

But you will need to store them on the server, at least until the email is sent. The $attachments parameter needs to be an array of strings that point to the file location for them to be attached, so we’ll still need to upload the files, but after they were attached we can just delete them.
Here’s an example :

if(isset($_POST['submit']) && strpos($_SERVER['HTTP_REFERER'], 'https://example.com/custom-file/') !== false) {
    $to = '[email protected]'; // Replace with your own email address
    $subject = $_POST['subject']; // Get the value of the subject field from the form
    $message = "Name: " . $_POST['name'] . "<br><br>";
    $message .= "Email: " . $_POST['email'] . "<br><br>";
    $message .= "Message: " . $_POST['message'] . "<br><br>";

    $headers = array('Content-Type: text/html; charset=UTF-8');

    $attachments = array();

    // Handle the uploaded file
    if ($_FILES['image']['error'] == UPLOAD_ERR_OK) {
        $tmp_name = $_FILES['image']['tmp_name'];
        $filename = basename($_FILES['image']['name']);
        $destination = sys_get_temp_dir() . "https://wordpress.stackexchange.com/" . $filename; // Use system temp directory

        // Move the file to the temporary directory
        if (move_uploaded_file($tmp_name, $destination)) {
            $attachments = array($destination);
        }
    }

    if (wp_mail($to, $subject, $message, $headers, $attachments)) {
        foreach($attachments as $file) {
            unlink($file); // Remove file from temp directory after sending
        }
        wp_redirect('/thank-you-contact-form-sent'); // Replace with the URL of your thank-you page
        exit();
    } else {
        foreach($attachments as $file) {
            unlink($file); // Remove file from temp directory after sending
        }
        wp_redirect('/sorry-contact-form-not-sent'); // Replace with the URL of your sorry page
        exit();
    }
}

This still doesn’t handle validation, but you can see the logic in it.