如何将表单作为 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
有一个 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