DEV Community

Discussion on: How to implement email functionality with Node.js, React.js, Nodemailer, and OAuth2

Collapse
 
jlong4223 profile image
Jared Long • Edited

Hey not sure if you've already figured out the react portion of this question but with react-hook-form and files, all you'd have to do is add an input like this to your form:

<input type="file" {...register("file")} />
Enter fullscreen mode Exit fullscreen mode

If you throw a console.log of the data in your onSubmit, you should see the file info there. I'll follow up later on the nodemailer side!

Collapse
 
oicydwa profile image
Chris • Edited

I have that part figured out already. I can get the data to my API, but what I can't figure out is how to make the 'file' attach with nodemailer. In my browser I see the file being sent like this:
"documentsUpload: FileList
0: File {name: 'Email Attachment test.txt', lastModified: 1647400270450, lastModifiedDate: Tue Mar 15 2022 22:11:10 GMT-0500 (Central Daylight Time), webkitRelativePath: '', size: 20, …}
length: 1"
But the data sent is blank:
"documentsUpload: { '0': {} }"
And nothing comes through on the email attachments.

Thread Thread
 
jlong4223 profile image
Jared Long • Edited

Yeah I'm actually running into the same thing. I can see the file updating when I log it but when I send it, it goes through blank. Not super sure why that's happening yet. I'm going to try and see If throwing together a custom onChange for this file input helps. Not sure what's happening in the background of react-hook-form with sending files.

Thread Thread
 
oicydwa profile image
Chris • Edited

I actually got this figured out LATE last night. It was NOT a simple solution and was very picky.

Thread Thread
 
jlong4223 profile image
Jared Long

That’s awesome! You mind sharing? Really curious to see what you came up with

Thread Thread
 
oicydwa profile image
Chris • Edited

This works with multi-file attachments too.

<Input
   type="file"
   ref={register}
   multiple
   {...register('file')}
   name={'file'}
   onChange={handleChange}
/>
Enter fullscreen mode Exit fullscreen mode

My handleChange()

const handleChange = async (e) => {
    setValue('file', e.target.value.files, {shouldDirty: true});
  }
Enter fullscreen mode Exit fullscreen mode

So, in my API calling method I did:

const fileUpload = require("express-fileupload"); // I don't know why
  app.use(express.urlencoded({ extended: true })); // But this is required. I dropped it
  app.use(fileUpload({
    createParentPath: true                        // and it stopped working.
  }));

 const sendEmail = async (data) => {
    let form = document.querySelector('form');
    const formData = new FormData(form);

    const {file} = data;

    for (let [index, value] of Object.entries(file)){
      formData.append(value.name, file[index]);
    }

    axios({
      method: 'post',
      url: 'http://localhost:3001/send',
      data: formData,
    });
  }
Enter fullscreen mode Exit fullscreen mode

and on the backend:

app.post('/send', async (req, res) => {

  const docs = Object.keys(req.files).map(key => {
    return {
      filename: req.files[key].name,
      content: req.files[key].data
    }
  });

  let mailOptions = {
    from: 'whoever@whereever.net',
    to: 'to-mail@mail.go',
    subject: `Message from: Whoever`,
    html: '<html></html>',
    attachments: docs // <--- All you need here!!
  };

  transporter.sendMail(mailOptions, function (err, data) {
    if (err) {
      res.json({
        status: 'fail',
      });
    } else {
      console.log('== Message Sent ==');
      res.json({
        status: 'success',
      });
    }
  });
});
Enter fullscreen mode Exit fullscreen mode
Thread Thread
 
jlong4223 profile image
Jared Long

Nice! Solid work. Glad you figured it out and thanks for sharing

Thread Thread
 
oicydwa profile image
Chris

I edited it a dozen times to make sure I had it just right, for posterity. I really hope this helps someone later, because it was a pain to figure out, and searching yielded bits and pieces, but NOTHING on the backend portion.

Thread Thread
 
jlong4223 profile image
Jared Long

Yeah it definitely will. I had a hard time finding quality full stack nodemailer stuff before putting this article together with bits and pieces that I found that worked. What really surprised me is how you were able to receive the file data on the api without needing a middleware package like multer. I’ll for sure be trying this.

Thread Thread
 
oicydwa profile image
Chris

I had to update. I took a part out I thought was no longer needed, and I was wrong. I guess there is your middleware you were talking about.

Thread Thread
 
vipcode786 profile image
VipCode786

Thanks @chris and @jlong4223 for sharing this information.