Apps Script로 시트 값이 바뀌면 메일을 보내도록 만들었는데, 메일이 안 오거나 받은편지함이 아니라 스팸함에 들어가는 경우가 있습니다. 커뮤니티에도 같은 질문이 반복됩니다. 이 글은 테스트 계정 3개로 2026-10-13에 직접 재현한 결과를 정리했습니다. 확인 기준일은 2026-10-14입니다.
이럴 때 이 글을 읽으세요
시트에 입력하면 자동으로 메일이 나가도록 만들었는데 실제로 받은 사람이 없다고 하거나, 시간에 맞춰 보내는 메일이 중간에 멈춘 것 같을 때입니다. 특히 받는 주소가 Outlook이나 회사 메일이라면 아래 4번 항목을 먼저 보세요.
결론 먼저: 실패처럼 보이는 문제는 네 가지로 나뉩니다
첫째, 처음 실행할 때 권한 승인이 필요한 경우입니다. 둘째, 잘못된 주소처럼 오류가 나는 경우입니다. 셋째, 시간 기반 트리거는 이번 재현에서 정상 동작했습니다. 넷째, 받는 쪽 메일함이 정크로 분류하는 경우입니다. 이 중 네 번째는 오류 없이 발송되기 때문에 실패를 알아차리기 가장 어렵습니다.
커뮤니티에서 반복되는 질문
아래 질문들은 제가 재현 주제를 고를 때 근거로 삼은 글입니다. 질문 내용은 원글을 요약한 것이고, 제 테스트로 확인한 것은 시간 트리거 건뿐입니다.
- MailApp.sendEmail이 시간 기반 트리거에서 조용히 실패한다는 질문 (Reddit)
- MailApp 메일이 도착하지 않는다는 질문 (Google Apps Script 커뮤니티)
- 일일 발송 한도에서 스크립트가 멈춘다는 질문 (Google Groups)
재현 환경
| 항목 | 내용 |
|---|---|
| 발신 계정 | Gmail 계정 2개, dreamwiz.com 주소로 로그인한 구글 계정 1개 |
| 수신 | Outlook.com 계정 1개 (별칭 주소 포함) |
| 실행 방식 | 시트 편집 트리거, 1분 간격 시간 트리거, 수동 실행 |
| 기록 | 시트 로그 열, Outlook 받은편지함과 정크 메일함, 메일 원본 헤더 |
함정 1: 처음 실행하면 권한 승인 창이 뜹니다
스크립트를 처음 실행하면 "승인 필요" 창이 뜨고, 메일 발송과 시트 접근 권한을 요청합니다. 본인이 만든 프로젝트라도 "확인되지 않은 앱" 경고가 나올 수 있습니다. 제 테스트에서는 고급 메뉴에서 프로젝트 이동을 눌러 승인을 마쳤습니다. 트리거는 승인이 끝난 뒤 setup 함수를 한 번 실행해야 만들어집니다.
함정 2: 잘못된 주소는 조용히 넘어가지 않습니다
받는 주소를 not-an-email처럼 잘못 넣으면 "Invalid email" 오류가 바로 발생했습니다. 오류를 잡지 않으면 실행 로그에만 남으므로, 아래 예시처럼 try와 catch로 감싸고 시트에 기록해 두는 것이 좋습니다.
함정 3: 일일 한도는 메일 1통마다 줄어듭니다
발송 전 남은 한도는 98이었고, 수신자 1명에게 한 통을 보낸 뒤 97이 됐습니다. 공식 할당량 문서는 소비자 계정에서 하루 수신자 100명이라고 안내합니다. 한도 초과 오류는 재현하지 않았습니다. 발송 전에 MailApp.getRemainingDailyQuota()로 남은 수를 확인하면 한도에 걸리기 전에 멈출 수 있습니다.
확인한 것: 1분 간격 시간 트리거는 5통 모두 발송
1분마다 실행되는 시간 기반 트리거를 걸고 기다렸더니 5번 모두 OK로 실행되었고 메일 5통이 도착했습니다. 커뮤니티 글에 있던 "시간 트리거에서 조용히 실패한다"는 현상은 이 조건에서는 재현되지 않았습니다. 다만 이것은 개인 계정 한 곳에서 한 번 해 본 결과라서, 다른 환경에서도 같다고 단정하지는 않겠습니다.
함정 4: 받는 쪽 메일함이 정크로 분류합니다
재현 과정에서 가장 시간이 많이 든 부분입니다. 발신 계정 A에서 Outlook 주소로 처음 보낸 메일은 오류 없이 발송되었지만 정크 메일함에 들어갔습니다. 원본 헤더를 보니 SPF, DKIM, DMARC 인증은 모두 통과했고, 스팸 점수(SCL)는 5로 찍혀 있었습니다. 인증은 모두 통과했지만 스팸 점수(SCL)가 5여서 정크로 분류된 것으로 보입니다. 세부 원인은 확인하지 못했습니다.
이후 정크 메일을 "정크 아님"으로 보고하고 같은 계정에서 다시 보내자 받은편지함으로 갔습니다. 계정 B는 첫 메일 2통이 정크로 갔고, 정크 아님 보고 후 재발송은 받은편지함으로 갔습니다. 헤더는 확인하지 않았습니다. 반면 발신 계정 C는 정크 아님 보고 후에도 재발송이 정크에 남았습니다. 계정 C 메일 상단에는 구글 중계 주소가 표시되고 "Unverified"가 떴습니다. dreamwiz.com에는 DMARC 기록이 없었고, SPF에는 _spf.google.com이 포함되어 있었습니다. 계정 C의 원본 헤더는 보지 못해서 원인은 확정하지 못했습니다.
점검 체크리스트
- 처음 실행 후 권한 승인과 트리거 생성을 확인합니다.
- 발송 코드를 try와 catch로 감싸고 시트에 OK와 ERR을 기록합니다.
- 발송 전 남은 한도를 기록합니다.
- 중요한 알림이면 Outlook 같은 수신 서비스에서 받은편지함에 도착했는지 확인합니다.
- 정크로 가면 "정크 아님"으로 보고하고 같은 발신자로 다시 보내서 결과를 비교합니다.
- 발신 주소가 구글 계정 주소인지, 다른 주소로 연결한 것인지 확인합니다.
예시 코드
아래 코드는 제가 재현에 쓴 구조를 줄인 것입니다. 시트_ID와 받는 주소는 직접 바꿔 쓰세요.
function setup() {
const ss = SpreadsheetApp.openById('시트_ID');
ScriptApp.getProjectTriggers().forEach(t => ScriptApp.deleteTrigger(t));
ScriptApp.newTrigger('onEditHandler').forSpreadsheet(ss).onEdit().create();
}
function onEditHandler(e) {
const log = SpreadsheetApp.openById('시트_ID').getSheets()[0];
const quota = MailApp.getRemainingDailyQuota();
try {
MailApp.sendEmail('받는주소@example.com', '알림 ' + new Date().toISOString(), '행 ' + (e && e.range ? e.range.getRow() : '시간 트리거') + ' 실행');
log.appendRow([new Date().toISOString(), 'OK', quota]);
} catch (err) {
log.appendRow([new Date().toISOString(), 'ERR', err.message, quota]);
}
}
직접 해 본 것과 못 해 본 것
위 내용은 2026-10-13에 테스트 계정 3개와 Outlook 계정 1개로 재현한 결과입니다. 원본 헤더는 계정 A의 정크 메일만 확인했고, 계정 B와 C는 메일 화면 표시로만 확인했습니다. 제가 찾은 자료에서는 Outlook의 세부 판단 기준을 확인하지 못해서 원인을 확정하지 못했습니다. 한도와 메뉴 위치는 2026-10-14 기준입니다.
참고한 공식 문서
'업무 자동화' 카테고리의 다른 글
| 파이썬 크롤링 403 Forbidden 에러 원인과 해결법 (0) | 2026.10.27 |
|---|---|
| 구글시트 값이 바뀌면 메일을 자동 발송하는 Apps Script 기초 (0) | 2026.10.11 |
| Zapier, Make, IFTTT 무료 플랜 한도 비교: 직장인 개인 업무 자동화 도구 선택 가이드 (0) | 2026.10.08 |