기본 콘텐츠로 건너뛰기

[지메일 팁 1] 지메일에서 예약전송하는 방법

지메일이 좋은 이유는, 지메일에서 제공하는 기본적인 기능외에도 사용자들이 필요로하는 유용한 기능들을 직접 추가할 수 있는 Open API 들을 제공하고 있다는 것입니다. 3rd party 플러그인 모듈들도 다 이런 API 를 이용하여 개발한 것으로 보입니다.

지메일에서 예약 전송을 이용하는 방법에는 두가지가 있습니다.

목차




Google 스크립트와 Google 스프레드시트를 이용한 나만의 예약 전송 기능을 만들어 활용하는 방법


구글 문서도구 스프레드시트의 스크립트 기능을 활용하면 다양하고 유용한 유틸리티를 만들 수 있습니다. 이 문서에서 소개하는 내용은 간단하게 구글문서 도구에서 내 스프레드시트 (예, My Gmail Scheduler) 를 작성하여 공개된 구글 스크립트를 삽입하여 내 지메일을 예약 전송하는 방법에 대해서 소개하고자 합니다.

아래 스프레드시트(My Gmail Scheduler)에서 보는 것과 같이, 지메일에서 작성중인 이메일 (초안 상태)들에 대해서 원하는 시간에 예약 일정을 설정하여 ‘Gmail Scheduler’ 스크립트를 수행하면 예약전송 OK


예약전송 스크립트 스프레드시트 만드는 순서

1. 스프레드시트 ‘My Gmail Scheduler’ 생성
2. 스프데드시트 -> ‘도구’ -> 스크립트 편집기 수행


3. 아래 스크립트 코드 입력

/* This Google Script was written by Amit Agarwal */

/* Web: http://www.labnol.org/?p=24867            */

/* Apps Script Development: http://ctrlq.org      */

/* Please retain this message in your copy        */

function onOpen() {
 var ss = SpreadsheetApp.getActiveSpreadsheet();
 var menu = [
   {name: "Step 1: Authorize", functionName: "authorize_"},
   {name: "Step 2: Fetch Messages", functionName: "initialize_"},
   {name: "Step 3: Schedule Messages", functionName: "setSchedule_"},
   {name: "Cancel Pending Jobs", functionName: "cancelJobs_"}
 ];  
 ss.addMenu("Gmail Scheduler", menu);
}

function authorize_() {  
 deleteTriggers_();
 SpreadsheetApp.getActive().toast("Authorization successful. Please choose Step 2 to fetch the Gmail drafts into the spreadsheet.");
}

function fetchDraftMessages_() {
 var sheet = SpreadsheetApp.getActiveSpreadsheet();
 var drafts = GmailApp.getDraftMessages();
 if (drafts.length > 0) {
   var rows = [];    
   for (var i=0; i
     if (drafts[i].getTo() !== "") {
       rows.push([drafts[i].getId(), drafts[i].getTo(), drafts[i].getSubject(), "", ""]);
     }
   }
   sheet.getActiveSheet().getRange(2,1,rows.length,5).setValues(rows);
   sheet.toast("Excellent. Now please enter the date and time when you would like these messages to be delivered.");
 } else {
   sheet.toast("We could not find any messages in your Gmail drafts folder.");
 }
}

function cancelJobs_() {
 deleteTriggers_();
 var sheet = SpreadsheetApp.getActiveSheet();
 var data  = sheet.getDataRange().getValues();
 for (var row=1; row
   sheet.getRange("E"+(row+1)).setValue("Not Scheduled");
 }
 SpreadsheetApp.getActive().toast("There are no pending messages in queue.");
}

function initialize_() {
 deleteTriggers_();
 clearSheet_();  
 fetchDraftMessages_();
}

function clearSheet_() {
 var sheet = SpreadsheetApp.getActiveSheet();
 sheet.getRange(2, 1, sheet.getLastRow()+1, 5).clearContent();
}

function setSchedule_() {
 deleteTriggers_();
 try {
   var sheet = SpreadsheetApp.getActiveSheet();
   var data  = sheet.getDataRange().getValues();
   var time  = new Date().getTime();
   var code  = [];
   for (var row in data ) {     
     if (row != 0) {
       var schedule = data[row][3];
       if ( schedule !== "" ) {
         if ( schedule.getTime() > time ) {
           ScriptApp.newTrigger("sendMails")
           .timeBased()
           .at(schedule)
           .inTimezone(SpreadsheetApp.getActiveSpreadsheet().getSpreadsheetTimeZone())
           .create();
           code.push("Scheduled");
         } else {
           code.push("Date is in the past");  
         }
       } else {
         code.push("Not Scheduled");
       }
     }
   }
   for (var i=0; i
     sheet.getRange("E" + (i+2)).setValue(code[i]);
   }
   SpreadsheetApp.getActiveSpreadsheet().toast("The mails have been scheduled. You can close this sheet. For help, contact amit@labnol.org", "Success", -1);
 } catch (e) {
   SpreadsheetApp.getActive().toast(e.toString());
 }
}

function deleteTriggers_() {
 var triggers = ScriptApp.getProjectTriggers();
 for (var i=0; i
   if (triggers[i].getHandlerFunction() === "sendMails") {
     ScriptApp.deleteTrigger(triggers[i]);
   }
 }
}


function sendMails() {
 try {
   var sheet = SpreadsheetApp.getActiveSheet();
   var data  = sheet.getDataRange().getValues();
   var time  = new Date().getTime();
   for (var row=1; row
     if (data[row][4] == "Scheduled") {             
       var schedule = data[row][3];
       if ( schedule != "" ) {
         if ( schedule.getTime() <= time ) {
           var status = dispatchDraft_(data[row][0]);
           sheet.getRange("E"+(row+1)).setValue(status);
         }
       }
     }
   }
 } catch (e) {
   SpreadsheetApp.getActive().toast(e.toString());
 }
}

function dispatchDraft_(id) {
 
 try {
   
   var message = GmailApp.getMessageById(id);
   
   if (message) {
     
     var body = message.getBody();
     var raw  = message.getRawContent();
     
     /* Credit - YetAnotherMailMerge */
     
     var regMessageId = new RegExp(id, "g");
     if (body.match(regMessageId) != null) {
       var inlineImages = {};
       var nbrOfImg = body.match(regMessageId).length;
       var imgVars = body.match(/]+>/g);
       var imgToReplace = [];
       if(imgVars != null){
         for (var i = 0; i < imgVars.length; i++) {
           if (imgVars[i].search(regMessageId) != -1) {
             var id = imgVars[i].match(/realattid=([^&]+)&/);
             if (id != null) {
               id = id[1];
               var temp = raw.split(id)[1];
               temp = temp.substr(temp.lastIndexOf('Content-Type'));
               var imgTitle = temp.match(/name="([^"]+)"/);
               var contentType = temp.match(/Content-Type: ([^;]+);/);
               contentType = (contentType != null) ? contentType[1] : "image/jpeg";
               var b64c1 = raw.lastIndexOf(id) + id.length + 3; // first character in image base64
               var b64cn = raw.substr(b64c1).indexOf("--") - 3; // last character in image base64
               var imgb64 = raw.substring(b64c1, b64c1 + b64cn + 1); // is this fragile or safe enough?
               var imgblob = Utilities.newBlob(Utilities.base64Decode(imgb64), contentType, id); // decode and blob
               if (imgTitle != null) imgToReplace.push([imgTitle[1], imgVars[i], id, imgblob]);
             }
           }
         }
       }
       
       for (var i = 0; i < imgToReplace.length; i++) {
         inlineImages[imgToReplace[i][2]] = imgToReplace[i][3];
         var newImg = imgToReplace[i][1].replace(/src="[^\"]+\"/, "src=\"cid:" + imgToReplace[i][2] + "\"");
         body = body.replace(imgToReplace[i][1], newImg);
       }
     }
     
     var options = {
       cc          : message.getCc(),
       bcc         : message.getBcc(),
       htmlBody    : body,
       replyTo     : message.getReplyTo(),
       inlineImages: inlineImages,
       attachments : message.getAttachments()
     }
     
     GmailApp.sendEmail(message.getTo(), message.getSubject(), body, options);
     message.moveToTrash();
     return "Delivered";
   } else {
     return "Message not found in Drafts";
   }
 } catch (e) {
   return e.toString();
 }
}

4. 스크립트 저장 및 실행
  1). 반드시 위 스크립트 코드를 입력한 후 저장 버튼을 클릭
  2). 저장 완료후, 실행->onOpen 함수를 수행  


5. 스크립트 onOpen 이 정상 수행이 되면, ‘내 지메일 예약 전송' 스프레드시트 메뉴에 ‘Gmail Scheduler’ 가 새롭게 생성이 됩니다.


6. 지메일에서 예약 전송하기 위한 메일 메시지들을 작성 후 전송하지 않고 초안(Draft) 상태 (임시보관함에 저장)로 저장하기



7. 스프레드시트에서 예약 전송 메시지 가져오기
  - 메뉴 -> Gmail Scheduler-> Step2: Fetch Messages 수행

8. 지메일에 예약전송 대상이 되는 메시지의 header 정보가 표시가 되고, 시트의 ‘D’ 컬럼에서 예약 전송하고자 하는 메시지를 선택 원하는 예약 일자를 입력 (예, 2014-08-01 08:00:00) 반드시 날짜 (YYYY-MM-DD) 와 시간 (HH:MM:SS) 을 입력해야 함


8번 과정을 통해서 지메일 예약이 정상 설정이 되면 스프레드시트는 닫기를 한 후, 나중에 다시 오픈하여 ‘E’ 컬럼을 확인하여 전송 상태 유무를 확인 할 수 있습니다. 정상으로 전송이 되면 ‘E’ 컬럼에 Delivered 표시가 됩니다.

크롬스토어에서 3rd party 앱을 설치하여 사용하는 방법이 있습니다.


크롬스토어에서 무료로 설치할 수 있는 예약전송의 대표적인 앱  Boomerang 을 크롬브라우저에서 설치하시면 됩니다.

크롬 브라우저에서 지메일 로그인 후, Boomerang 앱이 정상 설치 되면 아래 이미지에서와 같이 지메일 상단 오른쪽에 Boomerang 아이콘이 보여야 합니다.


편지쓰기시 하단에 ‘Send Later’ 라는 버튼이 보입니다. 이 버튼을 클릭하여 예약을 원하는 날짜및 시간을 입력하여 전송 하면 됩니다.

자세한 사항은 구글문서 참조

댓글

이 블로그의 인기 게시물

Uber의 Software Factory에서 배울 점: AI 에이전트는 ‘비용’이 아니라 ‘운영 설계’의 문제다

Uber의 Software Factory에서 배울 점: AI 에이전트는 ‘비용’이 아니라 ‘운영 설계’의 문제다 Uber Engineering이 공개한 “Running a Software Factory Efficiently at Uber Scale” 글은 단순한 AI 코딩 도구 소개가 아닙니다. 핵심은 AI 에이전트를 개발 현장에 많이 쓰면서도 비용을 통제하기 위한 운영 구조 입니다. 저는 이 글을 보면서 개인용 AI 오케스트레이션, 특히 제가 정리하고 있는 CPAO(Cost-aware Personal Agentic Orchestration) 와 매우 가까운 문제의식을 느꼈습니다. 규모는 Uber처럼 크지 않더라도, 개인·소규모 조직도 이제 AI를 “가끔 쓰는 도구”가 아니라 “반복 업무를 맡기는 업무팀”으로 운영해야 하는 단계에 들어섰기 때문입니다. 1. Uber가 말하는 AI Software Factory Uber는 AI 도구가 소프트웨어 개발 전 과정에 들어와 있다고 설명합니다. 코드 작성, 코드 리뷰, CI 실패 복구, 버그 분석, 온콜 알림 처리, 유지보수 PR 생성 등 여러 업무가 에이전트 기반으로 움직이고 있습니다. 인상적인 것은 사용량 증가입니다. Uber에 따르면 2026년 2월부터 8월까지 주간 활성 사용자는 7배, 주간 에이전트 요청은 9.4배 증가했습니다. 그런데 총 AI 비용은 4월 이후 비교적 안정화됐다고 합니다. 동일 모델 기준으로 보면 1,000개 요청당 비용은 피크 대비 약 34%, 세션당 비용은 6월 피크 대비 52% 낮아졌다고 합니다. 즉, Uber의 방향은 “AI를 덜 쓰자”가 아닙니다. 오히려 더 많이 쓰되, 낭비되는 턴·요청·토큰을 줄이는 방식 입니다. 2. 핵심은 비용 방정식이다 Uber는 AI 에이전트 비용을 다음과 같은 식으로 분해합니다. 총비용 = 사용자 수 × 세션/사용자 × 턴/세션 × 요청/턴 × 토큰/요청 × 토큰당 가격 이 식이 중요한 이유는 AI 비용을 막연한 “...

[알아두면 쓸모 있는 구글 문서 팁] 문서 공유시- 사용자 이름 대신에 익명의 동물이 표시 되는 이유와 동물 종류

구글 드라이브에는 다른 유사 서비스에서는 제공하지 않는 구글 만의 유니크한 기능들이 있다 구글 문서를  불특정 다수에게 전체 공개로 공유할 수 있습니다. 불특정인이 구글 문서에 접속한 경우 익명의 동물로 표시됩니다.  ' 웹에 공개' 또는 '링크가 있는 사용자' 공유 설정을 선택하면 인식할 수 없는 이름이나 익명의 동물이 표시될 수 있습니다. 파일에서 인식할 수 없는 이름을 볼 수 있는 몇 가지 이유는 다음과 같습니다. 메일링 리스트와 파일을 공유합니다. Google 계정이 없는 사용자와 파일을 공유하며, 그 사용자가 다른 사용자에게 공유 초대를 전달했습니다. 내 파일을 수정할 수 있는 누군가가 파일을 다른 사용자와 공유했습니다. 다른 사용자가 자신의 Google 계정 이름을 변경했습니다. 공유 설정 페이지에서 해당 사용자 이름 위로 마우스를 이동하여 이메일 주소를 확인하세요. 익명의 동물 다른 사용자에게 개별적으로 보기 또는 수정 권한을 부여하거나 메일링 리스트에 속해 있는 경우에만 사용자 이름이 표시됩니다. 파일 권한을 '링크가 있는 사용자'로 설정하면 파일을 보고 있는 사용자의 이름이 표시되지 않습니다. 대신 다른 사용자가 익명으로 라벨이 지정되어 표시되고 각 익명 사용자는 다양한 익명의 동물로 나열됩니다. 파일 권한을 '링크가 있는 사용자'로 설정했지만 특정 사용자와 파일을 공유하는 경우 파일을 공유한 사용자의 이름이 표시됩니다. 그 외 다른 사용자가 파일을 볼 때는 익명으로 나타납니다. 비공개 파일의 익명 동물 파일 권한을 '링크가 있는 사용자'로 설정한 다음 이를 '특정 사용자'로 변경하면 다음과 같은 경우 여러 익명의 동물이 표시될 수 있습니다. 누군가 파일을 여러 번 여는 경우에는 익명의 동물 목록에서 오래되고 연결이 끊긴 세션을 강제 종료하는 데 조금 시간이 걸릴 수 있습니다. 누군가 온...

Claude Fable 5.1 프롬프트 가이드: 쉽게 쓰는 AI 지시문 작성법

Claude Prompting Guide Claude Fable 5.1 프롬프트 가이드: 쉽게 쓰는 AI 지시문 작성법 Anthropic의 공식 문서는 Claude Fable 5.1을 더 잘 쓰기 위한 프롬프트 작성법을 설명합니다. 개발자용 문서라 조금 어렵지만, 핵심은 간단합니다. AI에게 “무엇을, 어느 정도로, 어떤 방식으로 끝낼지”를 더 분명히 알려주라는 것입니다. 출처: Anthropic Claude Platform Docs 한눈에 보는 핵심 작업 난이도에 맞게 AI의 “생각하는 정도”를 조절한다. 긴 작업에서는 중간 진행 상황을 사용자에게 알려달라고 요청한다. 독립적인 도구 호출은 한 번에 묶어서 처리하게 한다. 대화 기록은 중간에 고치지 말고 계속 뒤에 붙이는 방식이 안전하다. 글이 너무 길거나 딱딱하면 쉬운 문장과 구조를 요청한다. 작업을 시켰다면 끝까지 완료하고 검증하게 한다. 1. “생각하는 정도”를 작업에 맞게 정하라 Claude Fable 5.1에는 작업에 얼마나 많은 추론을 쓸지 정하는 effort 개념이 있습니다. 쉽게 말하면 AI에게 “빨리 대답할지, 더 깊게 생각할지”를 조절하는 장치입니다. 낮은 effort 간단한 요약, 분류, 짧은 답변처럼 빠른 처리가 중요한 작업 중간 effort 품질과 비용의 균형이 필요한 일반 업무 높은 effort 코딩, 분석, 복잡한 문서 작성처럼 실수가 비싼 작업 매우 높은 effort 긴 산출물이나 중요한 의사결정 보조 작업 문서의 조언은 명확합니다. 무조건 가장 높은 설정을 쓰지 말고, 실제 업무에서 품질·속도·비용을 비교해보라는 것입니다. AX 컨설팅 관점에서는 이 부분이 중요합니다. AI도 직원처럼 업무 난이도에 맞는 투입 시간이 필요합니다. 2. 오래 걸...

GPT-6 Astra 공개 내용 쉽게 해설: AI가 “대답하는 도구”에서 “일을 수행하는 동료”로

※ 아래 내용은 OpenAI가 공개한 GPT-6 Astra 소개 페이지의 주장을 바탕으로 쉽게 풀어쓴 해설입니다. 벤치마크 수치는 제조사가 제시한 조건과 측정 방식에 따라 달라질 수 있습니다. 한 줄 요약 GPT-6 Astra는 단순히 글을 잘 쓰는 모델을 넘어, 웹 브라우저와 컴퓨터를 직접 사용하고 여러 단계의 업무를 끝까지 수행하는 것을 목표로 한 모델입니다. 1. GPT-6 Astra는 무엇이 달라졌나? OpenAI는 GPT-6 Astra를 새로운 세대의 지능 모델이라고 소개합니다. 핵심은 지식량만 늘리는 것이 아니라 컴퓨터 사용, 웹 탐색, 소프트웨어 개발, 과학 연구, 사이버보안, 전문 업무 를 실제 작업 흐름 속에서 수행하도록 설계했다는 점입니다. 기존 챗봇이 질문에 답하고 결과물을 만들어 주는 데 집중했다면, Astra는 사용자의 목표를 이해한 뒤 브라우저를 열고, 자료를 찾고, 문서를 작성하고, 결과를 점검하는 식의 다단계 업무 수행 을 강조합니다. 2. 가장 중요한 변화: AI가 컴퓨터를 사용한다 소개 페이지의 표현을 쉽게 바꾸면 다음과 같습니다. 온라인 자료를 찾아 요약하기 문서·스프레드시트·프레젠테이션 만들기 웹사이트를 만들고 실제 화면에서 품질 점검하기 과학 데이터를 분석하고 그래프 만들기 양식 입력, 예약 검색, 상품 비교 같은 반복 업무 수행하기 이 변화는 “AI에게 무엇을 물어볼까?”에서 “AI에게 어떤 업무를 맡길까?”로 사용 방식이 이동한다는 뜻입니다. 프롬프트 한 번의 답변보다 목표·권한·검토 지점·완료 조건 을 설계하는 일이 중요해집니다. 3. 업무 성능에 대한 OpenAI의 주장 영역 공개 페이지에 제시된 내용 실무적으로 읽는 법 컴퓨터 사용 화면을 이해하고 브라우저·업무 도구를 조작 사람이 하던 반복적인 클릭·입력 업무를 위임할 가능성 소프트웨어 개발 코드 작성뿐 아니라 테스트와 수정까지 수행 코딩 보조를 넘어 이슈 해결 사이클에 참여 전문 업무 문서·스프레드시트·발표자료를 템플릿에 맞춰 생성 회사 ...

[Google이 교육용 G Suite 을 위한 LMS 연동 키트 - Course Kit 베타 공개]

Google 이 드디어 G Suite for Eudcation 버전을 위한  LMS (Learning Management System) 연동을 위한 키트를 제공한다는 소식입니다.  현재는 베타 서비스로 베타 서비스 신청을 하면 서비스를 받을 수 있다고 합니다. 44개 언어로 제공이 된다고 합니다. 다행히도 한국어도 포함되어 있습니다. 자세한 사항은 아래 내용을 참고하시기 바랍니다.  효과적인 교수 및 학습을 위해서는 강사와 학생 간의 원활한 협력이 필요합니다. 올바른 기술과 교육은 이러한 연결을 용이하게하는 데 도움이 될 수 있습니다. 따라서 많은 대학, 대학, 학교 및 기타 교육 기관에서 강사 및 학생들에게 LMS (Learning Management System)를 제공합니다. 교육자와 학생들은 LMS를 사용하는 것 외에도 G Suite의 클라우드 기반 생산성 도구를 사용하여 실시간으로 만들고 공동 작업하고 통신합니다. 지금까지는 G Suite를 많은 LMS와 통합하는 쉬운 방법이 없었습니다. Course Kit 입력  - 강사가 Google 문서 도구 및 드라이브를 사용하여 과제를 수집하고, 학생들에게 더 빠르고 풍부한 피드백을 제공하고, 이미 사용중인 LMS 내의 강의 자료를 공유 할 수있게 해주는 무료 툴킷입니다.  Course Kit는 학습 도구 상호 운용성 (LTI) 표준 을 사용하여 구축되므로 LTI를 지원하는 모든 LMS를 쉽게 설정하고 사용할 수 있습니다. Course Kit에는 현재 할당 도구 및 파일 포함 도구가 포함되어있어 G Suite의 강력한 협업 기능을 교육 및 학습 워크 플로에 통합하기가 빠르고 안전합니다. 지난 학기 동안 더 높은 교육 기관을 통해 Course Kit를 시범 적으로 운영하여 현재 베타 프로그램을 통해 더 널리 사용하도록하고 있습니다. Course Kit의 과제 도구로 사려 깊은 피드백을 얻을 수있는 시간을 ...