[자동화] 스프레드 시트로 메일 뿌리기

히나·2025년 7월 15일

기록남기기

목록 보기
2/2

들어가기에 앞서

+ 7월 15일 - 해당 글이 업로드 되지 않은 사실을 발견하여 지금 올립니다.

구름톤 유니브 4기 지원자 모집을 시작했다. 따라서 서류 합격 메일을 보내야하는데, 솔직히 말해 하나하나 보낼 생각을 하니 매우 머리가 아프다.

자동화를 해봅시다.

데이터 가져오기

우선 합격자 리스트를 가져와야한다. 시트 아이디와 이름을 통해 값을 가져오자.

참고로 구글 스프레드 시트 링크 형식은 다음과 같다.

https://docs.google.com/spreadsheets/d/{시트아이디}/edit?gid=0#gid=0
const DATA_SHEET_ID = ""

const getCandidates = () => {
  const data = SpreadsheetApp.openById(DATA_SHEET_ID).getSheetByName("시트 이름").getDataRange().getValues();

  return data.slice(2)
}

이렇게 하면 A1 셀부터 데이터가 있는 셀까지의 데이터를 이중 배열로 가져온다.

나는 getCandidates()에서 리턴하게 전에 앞의 두 줄을 날렸는데, 이는 시트에서 보기 좋도록 가장 첫 줄을 비우고 두 번째 줄에 열 이름을 적어두었기 때문이다.

이메일 생성하기

데이터를 가져왔으니 이제 이메일을 생성하면 된다. 나는 내가 보기 좋으려고 html 코드를 다음과 같이 작성했다.

<!DOCTYPE html>
<html lang="ko">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>서류 합격 안내</title>
    <style>
        body {
            font-family: Arial, sans-serif;
            margin: 0;
            padding: 0;
            background-color: #f4f4f4;
        }
        .container {
            max-width: 600px;
            margin: 20px auto;
            background: #ffffff;
            padding: 20px;
            border-radius: 10px;
            box-shadow: 0 2px 10px rgba(0, 0, 0, 0.1);
            text-align: center;
        }
        h2 {
            color: #333;
            font-size: 22px;
        }
        p {
            color: #555;
            font-size: 16px;
            line-height: 1.6;
            text-align: left;
        }
        .highlight {
            font-size: 18px;
            font-weight: bold;
            color: #000000;
        }
        .info-box {
            background: #f9f9f9;
            padding: 15px;
            margin: 10px 0;
            border-left: 5px solid #0073e6;
            text-align: left;
        }
        .footer {
            font-size: 14px;
            color: #888;
            margin-top: 20px;
            text-align: center;
        }
    </style>
</head>
<body>
    <div class="container">
        <img src="" alt="로고" style="width:100%; max-width:600px;">
        <h2>&#128226; [동아리 이름] 서류 합격 안내</h2>
        
        <p>안녕하세요, <b>[동아리 이름]</b>입니다.<br>
        먼저 저희 동아리에 관심을 가지고 지원해 주셔서 감사합니다.</p>

        <p>서류를 면밀히 검토한 결과, <span class="highlight">${name}님</span>께서 
        <b>서류 전형에 합격</b>하셨음을 알려드립니다! &#127881;</p>

        <div class="info-box">
            <b>&#128204; 면접 일정 안내</b><br>
            - <b>일시:</b> ${localString} <br>
            - <b>장소:</b> 중앙도서관 1층 세미나실5
        </div>

        <p><b>&#128161; 면접 전 준비해야 할 사항</b></p>
        <ul style="text-align: left; padding-left: 20px;">
            <li>면접 시간 <b>10분 전까지 도착</b>하여 참석 체크를 해주시길 바랍니다.</li>
            <li>면접 불참 또는 일정 조정이 필요하시면 <b>이메일</b>로 미리 알려주세요.</li>
        </ul>

        <p>다시 한 번 서류 합격을 축하드리며, 면접에서 좋은 모습으로 만나 뵙기를 기대하겠습니다!<br>
        궁금한 점이 있다면 언제든지 연락 주세요.</p>

        <div class="footer">
            &#128204; <b>[동아리 이름]운영진 드림</b><br>
            &#128231; 문의: <a href="mailto:9oormthon.univ.swu@gmail.com">메일 주소</a>
        </div>
    </div>
</body>
</html>

중간에 이름과 시간은 스프레드시트에서 가져온 데이터를 활용하기 위해 저렇게 작성해주었다. 실제로 활용하기 위해서는 다음과 같이 함수를 작성해야한다.

const getMailBody = (name, time) => {
  const localString = new Date(time).toLocaleString("ko-KR", {
  year: "numeric",
  month: "long",
  day: "numeric",
  weekday: "long",
  hour: "numeric",
  minute: "numeric",
  hour12: true, // 12시간제 사용 (오후 1:50 형태)
});
  return `html 코드`
}

특히 시간을 "YYYY년 MM월 DD일 요일 오후 hh시 mm분" 형식으로 보낼 수 있게 하려고 신경을 썼다. 덕분에 Date 객체에 대해 다시 알 수 있게 되었다. 하하...

main 함수 작성

데이터 가져오는 함수와 메일 생성하는 함수를 만들었으니 그 둘을 모두 실행할 함수를 작성해야한다. 특히 한 사람한테만 보내는 게 아니므로 getCandidates()함수로 가져온 배열에 map을 돌려줬다.

이때 GmailApp에서 sendEmail을 사용해주었다.

const main = () => {
  const candidates = getCandidates()

  candidates.map((candidate) => {
    const mailBody = getMailBody(candidate[1], candidate[4])

    GmailApp.sendEmail(candidate[2], MAIL_SUBJECT, "", { htmlBody: mailBody });
  })
}

이렇게 하고 원하는 메일 발송 시간에 트리거를 걸어주면 끝이다.

마치며

만들기 시작할 때는 꽤 힐 게 많을 거 같다 생각했는데 예측했던 것 보다 별거 없었다.
이후에 최합 때도 같은 코드를 활용하게 될 것 같다.

profile
git블로그와 티스토리를 떠돌다 벨로그에 정착하다.

0개의 댓글