如何将表单作为 PDF 附件发送到电子邮件(Nodemailer、React、Node.js)

How to send form as PDF attached to email (Nodemailer, React, Node.js)

有一个 React 表单。我想要实现的目标:我填写表格。我点击提交按钮。然后此表单应生成一个 PDF,该 PDF 作为附件通过 Nodemailer 发送。我已经实现了发送电子邮件和生成 PDF(可以下载),但我不知道如何将该 PDF 附加到电子邮件中。还有一个签名,我已经可以附加到 PDF 上了。我只想将此 PDF 作为电子邮件附件发送。现在当我提交时,它只为我下载 PDF(这很好)并且只发送一封简单的电子邮件(没有 PDF 附件)。

服务器:

app.post('/create-pdf', (req, res) => {
    pdf.create(pdfTemplate(req.body), {}).toFile('result.pdf', (err) => {
        if (err) {
            res.send(Promise.reject());
        }

        res.send(Promise.resolve());
    });
});
app.post('/api/contact', contact);
app.get('/fetch-pdf', (req, res) => {
    res.sendFile(`${__dirname}/result.pdf`);
});

节点邮件程序:

exports.contact = async (req, res) => {
    const htmlEmail = `
        <h1>Hello!</h1>
        `;

    const mailOptions = {
        from: req.body.name,
        to: 'xxxxxxxxxxxxxxxxxxx',
        subject: 'Message',
        html: htmlEmail,
        attachments: [{}],
    };

    const transporter = nodemailer.createTransport({
        host: 'smtp.ethereal.email',
        port: 587,
        auth: {
            user: 'xxxxxxxxxxxxxxx',
            pass: 'xxxxxxxxxxxxxxx',
        },
    });

    transporter.sendMail(mailOptions, (err, data) => {
        if (err) {
            res.json({
                status: 'fail',
            });
        } else {
            res.json({
                status: 'success',
            });
        }
    });
    return console.log('email sent');
};

客户:

class Contact extends React.Component {
    constructor(props) {
        super(props);
        this.state = {
            name: '',
            email: '',
            phone: '',
            message: '',
            trimmedDataURL: null,
            file: null,
        };
    }

    sigPad = {};
    clear = () => {
        this.sigPad.clear();
    };
    trim = (e) => {
        e.preventDefault();
        this.setState({ trimmedDataURL: this.sigPad.getTrimmedCanvas().toDataURL('image/png') });
        this.fileUpload(this.state.file).then((response) => {
            console.log(response);
        });
    };

    fileUpload(file) {
        const url = 'http://localhost:3000/create-pdf';
        const formData = new FormData();
        formData.append('file', file);
        const config = {
            headers: {
                'content-type': 'multipart/form-data',
            },
        };
        return post(url, formData, config);
    }

    handleSubmit(e) {
        e.preventDefault();

        axios({
            method: 'POST',
            url: '/api/contact',
            data: this.state,
        }).then((response) => {
            if (response.data.status === 'success') {
                console.log('success');
            } else if (response.data.status === 'fail') {
                console.log('not success');
            }
        });

        axios
            .post('/create-pdf', this.state)
            .then(() => axios.get('fetch-pdf', { responseType: 'blob' }))
            .then((res) => {
                const pdfBlob = new Blob([res.data], { type: 'application/pdf' });

                saveAs(pdfBlob, 'newpdf.pdf');
            });
    }

    render() {
        return (
                <div className="contact">
                            <h1>GET IN TOUCH</h1>
                            <div>
                                <form onSubmit={this.handleSubmit.bind(this)} method="POST">
                                    <label htmlFor="name">NAME</label>
                                    <br />
                                    <input
                                        onChange={this.onNameChange.bind(this)}
                                        value={this.state.name}
                                        type="text"
                                        name="name"
                                        placeholder="Your full name..."
                                    />

                                    <br />
                                    <label htmlFor="phone">PHONE</label>
                                    <br />
                                    <input
                                        onChange={this.onPhoneChange.bind(this)}
                                        type="text"
                                        name="phone"
                                        placeholder="Your phone number..."
                                        value={this.state.phone}
                                    />

                                    <br />

                                    <label htmlFor="email">EMAIL</label>
                                    <br />
                                    <input
                                        onChange={this.onEmailChange.bind(this)}
                                        type="text"
                                        name="email"
                                        placeholder="Your email address..."
                                        value={this.state.email}
                                    />

                                    <br />

                                    <label htmlFor="message">MESSAGE</label>
                                    <br />
                                    <textarea
                                        onChange={this.onMessageChange.bind(this)}
                                        type="text"
                                        name="message"
                                        value={this.state.message}
                                        rows="5"
                                    />

                                    <button className="contact-button" type="submit">
                                        Send
                                    </button>
                                    <button onClick={this.createAndDownloadPdf}>download</button>

                                    <br />
                                    <SignatureCanvas
                                        canvasProps={{ className: styles.sigPad }}
                                        backgroundColor="gray"
                                        ref={(ref) => {
                                            this.sigPad = ref;
                                        }}
                                    />
                                    <img
                                        alt=""
                                        className={styles.sigImage}
                                        src={this.state.trimmedDataURL}
                                        style={{ width: '50px' }}
                                    />
                                    <button className={styles.buttons} onClick={this.clear}>
                                        Clear
                                    </button>
                                    <button
                                        className={styles.buttons}
                                        onClick={this.trim}
                                        onChange={this.onFileChange.bind(this)}
                                    >
                                        Trim
                                    </button>
                                </form>
                            </div>
            </div>
        );
    }
    onNameChange(event) {
        this.setState({ name: event.target.value });
    }

    onEmailChange(event) {
        this.setState({ email: event.target.value });
    }

    onPhoneChange(event) {
        this.setState({ phone: event.target.value });
    }

    onMessageChange(event) {
        this.setState({ message: event.target.value });
    }

    onFileChange(e) {
        this.setState({ file: e.target.files[0] });
    }
}

export default Contact;
attachments: [
            {
                filename: 'result.pdf',
                path: '../grovespine/result.pdf',
            },
        ],

总是在我的文件夹中生成一个新的 result.pdf,只需将其附加到 nodemailer