NOTE: Incorrectly marked as duplicate, I am looking to upload AND send files via Ajax/jQuery, which the suggested duplicate does not answer.
I am new to form creation/submission, but have had success in creating a contact form using multiple fields types, and then submitting via Ajax to be emailed. However, I have come unstuck on the final part of this process, adding (multiple) attachments to be uploaded and included in the email.
I am working in Wordpress. To create the form, I am using a combination of HTML, jQuery, Ajax and jQuery validate plugin.
My step by step code is below, and I would really appreciate any guidance people can offer to implement this final piece of the jigsaw. I have experimented with the 'superglobal' variable $_FILES, but got lost pretty quickly. The email is sending correctly with all data from text/email/select fields, but I have no idea how to include the attachments also.
Thanks in advance!
HTML
<form class="contact-form" action="<?=esc_url(admin_url('admin-ajax.php'))?>" method="post" enctype="multipart/form-data">
    <input type="hidden" name="action" value="contact_form">
    <div class="field text">
        <input type="text" id="first_name" name="first_name" placeholder="First name">
        <label for="first_name">First Name</label>
    </div>
    <div class="field email">
        <input type="email" id="email" name="email" placeholder="Your email">
        <label for="email">Your email</label>
    </div>
    <div class="field select">
        <label for="select">Select</label>
        <select name="select">
            <option value="">Please Select</option>
            <option value="one">One</option>
            <option value="two">Two</option>
        </select>
    </div>
    <div class="field file">
        <input type="file" id="file" name="file" multiple>
        <label for="file">Choose files</label>
    </div>
    <div class="field submit">
        <button class="button" type="submit">Send</button>
    </div>
</form>
jQuery/Ajax validate/submit
// Form(s) submission
var form = $('.contact-form form');
var btn = form.find('.submit button');
// Validate form (uses jQuery validate plugin)
form.validate({
    // Rules
    rules:{
        first_name:{
            required: true,
        },
        email:{
            required: true,
            email: true,
        },
        select:{
            required: true,
        },
        file:{
            accepts: "application/pdf, image/*, text/plain, application/msword",
            extension: "pdf|doc|docx|txt|jpg|gif|png",
        },
    },
    // Error element
    errorElement: 'span',
});
// On submit
form.on('submit', function(e) {
    // Prevent button sending information / reloading page
    e.preventDefault();
    // If form is valid
    if (form.valid()) {
        // Ajax function
        $.ajax({
            type: 'post',
            enctype: 'multipart/form-data',
            url: form.attr('action'),
            data: form.serialize(),
            success: function(result) {
                var wasSuccessful = JSON.parse(result);
                // If successful
                if (wasSuccessful) {
                    console.log('success!');
                // If error
                } else {
                    console.log('error!');
                }
            }
        });
    }
});
Send form
function send_contact_form() {
    // To
    $to = 'name@domain.com';
    // Subject
    // Including date and time creates new thread in their Gmail inbox
    $subject = 'Website Contact Form - ' . date('d/m/Y H:i:s');
    // Form parts
    $message = [];
    $message['First name'] = $_POST['first_name'];
    $message['Email'] = $_POST['email'];
    $message['Select'] = $_POST['select'];
    $message['File'] = $_FILES; // This doesn't work!!!
    $message_str = '';
    foreach ($message as $label => $entry) {
        $message_str .= "—\n" . $label . ":\n" . $entry . "\n\n";
    }
    // Headers
    $headers = [];
    $headers[] = 'Reply-To: <' . $_POST['email'] . '>';
    // Compile email
    $result = wp_mail($to, $subject, $message_str, $headers);
    // Send back result (bool)
    // also calls die()
    wp_send_json($result);
}
add_action('wp_ajax_contact_form' , 'send_contact_form');
add_action('wp_ajax_nopriv_contact_form', 'send_contact_form');
