从react-hook-form上传的PDF文件无法使用SendGrid API打开
我有一个工作申请表,用户可以上传他们的简历,由react-hook-form处理。我可以将简历保存在状态中,并且可以将其作为请求的一部分发送到 sendgrid API,但是当您通过电子邮件收到附件时,附件将无法打开。
我已经这样做了很长时间,我不知道我做错了什么。非常感谢任何建议。到目前为止,这是我的代码:
// components/Careers_Application_Form.tsx
import React, { useState } from 'react'
import { useForm } from 'react-hook-form'
export default function Careers_Application_Form() {
const [file, setFile] = useState(null)
const [fileName, setFileName] = useState('')
function handleUploadFile(selectedFile) {
if (selectedFile.length > 0) {
let fileToLoad = selectedFile[0]
setFileName(fileToLoad.name)
let fileReader = new FileReader()
fileReader.onload = function (fileLoadedEvent) {
let file = fileLoadedEvent.target.result
setFile(file.toString('base64'))
}
fileReader.readAsDataURL(fileToLoad)
}
}
const {
register,
watch,
handleSubmit,
formState: { errors },
} = useForm({})
// Handle the submit
const onSubmit = (data) => {
handleUploadFile(data.resume)
SendToSendgrid(data)
setSubmitted(true)
console.log(errors)
}
// SENDGRID
async function SendToSendgrid(data) {
data.file = file
data.fileName = fileName
await fetch('/api/sendJobApplication', {
method: 'POST',
body: JSON.stringify(data),
}).then((res) => res.json())
}
return (
<form onSubmit={handleSubmit(onSubmit)}>
<input
type='file'
onChange={setFile}
placeholder='Upload Your Resume'
{...register('resume', {
required: true,
validate: {
lessThan10MB: (files) => files[0]?.size < 10000000 || 'Max 10MB',
acceptedFormats: (files) => files[0].type === 'application/pdf',
},
})}
/>
{errors.resume?.type === 'lessThan10MB' && (
<p>Error: Must Be Under 10MB</p>
)}
{errors.resume?.type === 'acceptedFormats' && (
<p>Error: Must Be A PDF</p>
)}
<input
type='submit'
value={'off she goes!'}
/>
</form>
)
}
这是 sendgrid API 文件:
// pages/api/sendJobAppication.ts
import mail from "@sendgrid/mail";
mail.setApiKey(process.env.SENDGRID_API_KEY);
export default async function sendOnboarding(req, res) {
const body = JSON.parse(req.body);
await mail.send({
to: `redacted`,
from: {
email: "redacted",
name: "Pixel Bakery Robot",
},
subject: `Job Application: ${body.first_name} ${body.last_name} – ${body.position}`,
templateId: "redacted",
dynamicTemplateData: {
// ...more
},
attachments: [
{
content: `${body.file}`,
filename: `${body.fileName}`,
type: "application/pdf",
disposition: "attachment",
},
],
});
console.log(res.status(200).json({ status: "Ok" }));
}
这是我尝试打开附件时发生的情况:
< img src="https://i.sstatic.net/Zs8De.png" alt="在此处输入图像描述">
I have a job application form where users upload their resumes, handled by react-hook-form. I can get the resume saved in state just fine, and I can send it as part of a request to the sendgrid API, but the attachment won't open when you receive it via email.
I've been at this for so long, I have no idea what I'm doing wrong. Any advice is much appreciated. Here's my code so far:
// components/Careers_Application_Form.tsx
import React, { useState } from 'react'
import { useForm } from 'react-hook-form'
export default function Careers_Application_Form() {
const [file, setFile] = useState(null)
const [fileName, setFileName] = useState('')
function handleUploadFile(selectedFile) {
if (selectedFile.length > 0) {
let fileToLoad = selectedFile[0]
setFileName(fileToLoad.name)
let fileReader = new FileReader()
fileReader.onload = function (fileLoadedEvent) {
let file = fileLoadedEvent.target.result
setFile(file.toString('base64'))
}
fileReader.readAsDataURL(fileToLoad)
}
}
const {
register,
watch,
handleSubmit,
formState: { errors },
} = useForm({})
// Handle the submit
const onSubmit = (data) => {
handleUploadFile(data.resume)
SendToSendgrid(data)
setSubmitted(true)
console.log(errors)
}
// SENDGRID
async function SendToSendgrid(data) {
data.file = file
data.fileName = fileName
await fetch('/api/sendJobApplication', {
method: 'POST',
body: JSON.stringify(data),
}).then((res) => res.json())
}
return (
<form onSubmit={handleSubmit(onSubmit)}>
<input
type='file'
onChange={setFile}
placeholder='Upload Your Resume'
{...register('resume', {
required: true,
validate: {
lessThan10MB: (files) => files[0]?.size < 10000000 || 'Max 10MB',
acceptedFormats: (files) => files[0].type === 'application/pdf',
},
})}
/>
{errors.resume?.type === 'lessThan10MB' && (
<p>Error: Must Be Under 10MB</p>
)}
{errors.resume?.type === 'acceptedFormats' && (
<p>Error: Must Be A PDF</p>
)}
<input
type='submit'
value={'off she goes!'}
/>
</form>
)
}
Here's the sendgrid API file:
// pages/api/sendJobAppication.ts
import mail from "@sendgrid/mail";
mail.setApiKey(process.env.SENDGRID_API_KEY);
export default async function sendOnboarding(req, res) {
const body = JSON.parse(req.body);
await mail.send({
to: `redacted`,
from: {
email: "redacted",
name: "Pixel Bakery Robot",
},
subject: `Job Application: ${body.first_name} ${body.last_name} – ${body.position}`,
templateId: "redacted",
dynamicTemplateData: {
// ...more
},
attachments: [
{
content: `${body.file}`,
filename: `${body.fileName}`,
type: "application/pdf",
disposition: "attachment",
},
],
});
console.log(res.status(200).json({ status: "Ok" }));
}
Here's what happens when I try to open the attachment:
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(1)
一个问题是您混合了同步和异步逻辑。删除两个
useState()
调用。当您设置它们的值时,直到下一次渲染之后您才会获得更新的值。因此,当handleUploadFile
返回并且您输入SendToSendgrid
时,文件和文件名值可能不正确。我会让handleUploadFile 仅返回一个[file, filename]
元组。然后在服务器端 - 您可能会将 base64 传递给 SendGrid。他们可能期待二进制...检查事物是多个点...一些可能帮助您调试的提示:
编辑:
看起来 SendGrid 确实需要 base64。
您可以直接使用变量,而无需将它们从字符串模板中取出:
One issue is that you're mixing synchronous and asynchronous logic. Remove the two
useState()
calls. When you set their values, you won't get the updated values until after the next render. So whenhandleUploadFile
returns and you enterSendToSendgrid
the file and fileName values are probably incorrect. I'd have handleUploadFile just return a tuple of[file, filename]
. Then on the server-side - you may be passing base64 to SendGrid. They may be expecting binary...Check things are multiple points... Some tips that may help you debug:
EDIT:
It looks like SendGrid does expect base64.
You can just use the variable directly without pulling them out of a string template: