Next.js로 포트폴리오 만들기
EmailJS 세팅하기
-
EmailJS 에 접속하여 회원가입 및 로그인을 한다.
-
Add New Service 클릭!

- 보낼 이메일 서비스 클릭! » Create Service 클릭!
여기서 정한 이메일 주소에서 가입한 내 주소로 메일을 보내준다. (결국 내가 나에게 보냄)

- Email Templates 클릭 ! » 마찬가지로 Create New Template 클릭!


여기에서 안에 있는 단어가 코딩할 때, name=”“으로 작성해주면, 작성자가 input 안에 넣은 값을 메일 내용에 넣어서 보내준다.
나는 default의 내용과 살짝 다르게 변형시켰는데, 나는 포트폴리오에 넣는 contact라서 내용을 더 예쁘게 다듬지는 않았다.
NextJS에 적용하기
- KEY와 VALUE를 .env 파일에 작성해준다.
값들은 모두 EmailJS 사이트에서 찾아볼 수 있다. menu에서 Email Services, Email Templates, Account 에서 각각 찾아보면된다.
- 여기에서 개인키는 private 키가 아니라 public 키를 찾아서 넣어주면 된다.
NEXT_PUBLIC_MAIL_TEMPLATE_KEY = Template_ID
NEXT_PUBLIC_NEXT_PUBLIC_MAIL_SERVER_KEY = Service_ID
NEXT_PUBLIC_MAIL_PRIVATE_KEY = public key
- 라이브러리 다운로드 및 선언
터미널에 install을 해주고나서
npm install @emailjs/browser --save
사용하고자 하는 파일에 import해주면 된다.
import emailjs from "@emailjs/browser";
- env 파일을 사용할 수 있도록 선언해준다.
const NEXT_PUBLIC_MAIL_TEMPLATE_KEY =
process.env.NEXT_PUBLIC_MAIL_TEMPLATE_KEY;
const NEXT_PUBLIC_NEXT_PUBLIC_MAIL_SERVER_KEY =
process.env.NEXT_PUBLIC_NEXT_PUBLIC_MAIL_SERVER_KEY;
const NEXT_PUBLIC_MAIL_PRIVATE_KEY = process.env.NEXT_PUBLIC_MAIL_PRIVATE_KEY;
- 이벤트를 함수로 처리해준다.
나는 타입스크립트를 이용하고 있기 때문에 조금 더 처리가 필요했다.
- form.current가 null일 경우, 경고창을 따로 띄워주며 sendForm 함수를 이용할 때 오류를 없애주었다.
const onSubmitForm = (event: { preventDefault: () => void }) => {
event.preventDefault();
if (form.current == null) {
alert("폼이 존재하지 않습니다.");
return;
}
try {
emailjs.sendForm(
NEXT_PUBLIC_NEXT_PUBLIC_MAIL_SERVER_KEY as string,
NEXT_PUBLIC_MAIL_TEMPLATE_KEY as string,
form.current,
NEXT_PUBLIC_MAIL_PRIVATE_KEY
);
alert("메일이 전송되었습니다.");
setInputName(""); // 여기에 있는 3개의 set함수는 메일 전송이 이루어진 이후 input 창의 내용을 지우기 위한 후처리이다.
setInputEmail("");
setMessage("");
} catch (error) {
alert("메일 전송에 실패하였습니다. ");
}
};
- input 태그에 name을 설정해준다.
아까 emailJS의 템플릿에서 본 것처럼 안에 있는 이름으로 사용해야한다.
전체 코드
import { useRef, useState } from "react";
import emailjs from "@emailjs/browser";
export default function Contact() {
const NEXT_PUBLIC_MAIL_TEMPLATE_KEY =
process.env.NEXT_PUBLIC_MAIL_TEMPLATE_KEY;
const NEXT_PUBLIC_NEXT_PUBLIC_MAIL_SERVER_KEY =
process.env.NEXT_PUBLIC_NEXT_PUBLIC_MAIL_SERVER_KEY;
const NEXT_PUBLIC_MAIL_PRIVATE_KEY = process.env.NEXT_PUBLIC_MAIL_PRIVATE_KEY;
const form = useRef<HTMLFormElement>(null);
const [inputName, setInputName] = useState<string>("");
const [inputEmail, setInputEmail] = useState<string>("");
const [message, setMessage] = useState<string>("");
const onSubmitForm = (event: { preventDefault: () => void }) => {
event.preventDefault();
if (form.current == null) {
alert("폼이 존재하지 않습니다.");
return;
}
try {
emailjs.sendForm(
NEXT_PUBLIC_NEXT_PUBLIC_MAIL_SERVER_KEY as string,
NEXT_PUBLIC_MAIL_TEMPLATE_KEY as string,
form.current,
NEXT_PUBLIC_MAIL_PRIVATE_KEY
);
alert("메일이 전송되었습니다.");
setInputName("");
setInputEmail("");
setMessage("");
} catch (error) {
alert("메일 전송에 실패하였습니다. ");
}
};
return (
<>
<section className="text-gray-600 body-font relative">
<div className="container px-5 py-24 mx-auto">
<div className="flex flex-col text-center w-full mb-12">
<h1 className="sm:text-3xl text-2xl font-medium title-font mb-4 text-gray-900">
CONTACT ME
</h1>
<p className="lg:w-2/3 mx-auto leading-relaxed text-base">메시지</p>
</div>
<form ref={form} onSubmit={onSubmitForm}>
<div className="lg:w-1/2 md:w-2/3 mx-auto">
<div className="flex flex-wrap -m-2">
<div className="p-2 w-1/2">
<div className="relative">
<label
htmlFor="name"
className="leading-7 text-sm text-gray-600"
>
Name
</label>
<input
type="text"
name="from_name"
className="w-full bg-gray-100 bg-opacity-50 rounded border border-gray-300 focus:border-indigo-500 focus:bg-white focus:ring-2 focus:ring-indigo-200 text-base outline-none text-gray-700 py-1 px-3 leading-8 transition-colors duration-200 ease-in-out"
required
value={inputName}
onChange={(e) => setInputName(e.target.value)}
/>
</div>
</div>
<div className="p-2 w-1/2">
<div className="relative">
<label
htmlFor="email"
className="leading-7 text-sm text-gray-600"
>
Email
</label>
<input
type="email"
name="reply_to"
required
className="w-full bg-gray-100 bg-opacity-50 rounded border border-gray-300 focus:border-indigo-500 focus:bg-white focus:ring-2 focus:ring-indigo-200 text-base outline-none text-gray-700 py-1 px-3 leading-8 transition-colors duration-200 ease-in-out"
value={inputEmail}
onChange={(e) => setInputEmail(e.target.value)}
/>
</div>
</div>
<div className="p-2 w-full">
<div className="relative">
<label
htmlFor="message"
className="leading-7 text-sm text-gray-600"
>
Message
</label>
<textarea
name="message"
className="w-full bg-gray-100 bg-opacity-50 rounded border border-gray-300 focus:border-indigo-500 focus:bg-white focus:ring-2 focus:ring-indigo-200 h-32 text-base outline-none text-gray-700 py-1 px-3 resize-none leading-6 transition-colors duration-200 ease-in-out"
value={message}
onChange={(e) => setMessage(e.target.value)}
></textarea>
</div>
</div>
<div className="p-2 w-full">
<button className="flex mx-auto text-white bg-indigo-500 border-0 py-2 px-8 focus:outline-none hover:bg-indigo-600 rounded text-lg">
<input type="submit" value="SEND" required />
</button>
</div>
<div className="p-2 w-full pt-8 mt-8 border-t border-gray-200 text-center">
<a className="text-indigo-500">sonrisa-bonita@naver.com</a>
<p className="leading-normal my-5">
경기도 용인시 기흥구 영덕동
</p>
<span className="inline-flex">
<a className="ml-4 text-gray-500">
<svg
fill="none"
stroke="currentColor"
stroke-linecap="round"
stroke-linejoin="round"
stroke-width="2"
className="w-5 h-5"
viewBox="0 0 24 24"
>
<rect
width="20"
height="20"
x="2"
y="2"
rx="5"
ry="5"
></rect>
<path d="M16 11.37A4 4 0 1112.63 8 4 4 0 0116 11.37zm1.5-4.87h.01"></path>
</svg>
</a>
<a className="ml-4 text-gray-500">
<svg
fill="currentColor"
stroke-linecap="round"
stroke-linejoin="round"
stroke-width="2"
className="w-5 h-5"
viewBox="0 0 24 24"
>
<path d="M21 11.5a8.38 8.38 0 01-.9 3.8 8.5 8.5 0 01-7.6 4.7 8.38 8.38 0 01-3.8-.9L3 21l1.9-5.7a8.38 8.38 0 01-.9-3.8 8.5 8.5 0 014.7-7.6 8.38 8.38 0 013.8-.9h.5a8.48 8.48 0 018 8v.5z"></path>
</svg>
</a>
</span>
</div>
</div>
</div>
</form>
</div>
</section>
</>
);
}
나는 tailwind block css를 이용하였다. 코드가 상당히 지저분해보인다는 단점을 가지고 있는 tailwindCSS… 이게 개인용 프로젝트이고 개인용 포트폴리오라 가능한 일인 것 같다.
vercel 배포시,
vercel 배포를 하면, local에서 작동이 잘되던 메일 전송이 안되는 걸 확인할 수 있다.
그건 바로 .env 파일을 보통 github에 올라가지 않도록 gitignore로 막아두기 때문인데,
이를 해결하기 위해서는 vercel에 프로젝트 안에 들어가서 settings 메뉴의 Environment Variables에서 아까 .env에 지정한 key와 value값 3개를 넣고 save해주면 된다!
