기본 콘텐츠로 건너뛰기

[지메일 팁 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’ 라는 버튼이 보입니다. 이 버튼을 클릭하여 예약을 원하는 날짜및 시간을 입력하여 전송 하면 됩니다.

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

댓글

이 블로그의 인기 게시물

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

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

10M 크기 이상의 PDF 문서나 PPT파일 업로드 후 분석하기 (팁)[13-Claude AI 로 블로깅하고 책쓰기]

Claude AI로 대용량 PDF 파일과 PPT 파일 분석하기 (팁) 이번엔 Claude AI를 활용하여 PDF와 PPT 파일을 분석하는 방법에 대해 알아보겠습니다. Claude AI의 장점과 제약사항 Claude AI는 PDF, DOCX, TXT, CSV 등의 파일을 업로드하여 분석할 수 있다는 큰 장점이 있습니다. 하지만 PPT 파일이나 10MB 이상의 파일은 업로드할 수 없다는 제약사항이 있죠. 그렇다면 PPT 파일이나 10MB가 넘는 PDF 파일(대부분의 논문 파일)은 어떻게 분석할 수 있을까요? 지금부터 알려드리는 팁을 활용해보세요! 대용량 (10M 이상) PDF 파일 분석하기 1. 무료 구글 드라이브 또는 유료 Google Workspace 계정의 구글 드라이브에 10MB 이상의 PDF 파일을 업로드합니다. 2. 해당 PDF 파일을 선택한 후 마우스 오른쪽 버튼을 클릭합니다. 3. '연결 앱' -> 'Google 문서'를 선택하면 PDF 내용이 모두 텍스트로 추출되어 Google 문서로 자동 변환됩니다. 4. 변환된 Google 문서에서 '파일' -> '다운로드' -> '일반 텍스트(txt)'를 선택하여 텍스트 파일로 저장합니다. 5. 생성된 텍스트 파일을 Claude AI에 업로드하면 분석이 가능해집니다. PPT 파일 분석하기 PPT 파일도 파워포인트나 Google 드라이브에서 열어 TXT 파일로 저장한 후 Claude AI에 업로드하면 분석할 수 있습니다. 이렇게 간단한 과정을 통해 Claude AI의 제약사항을 극복하고, 다양한 파일 형식을 분석할 수 있게 되었습니다. 여러분도 이 팁을 활용해 보시고, Claude AI의 강력한 분석 기능을 경험해 보세요! (*** Google 드라이브에서는 PDF 문서나 이미지 파일을 'Google 문서' 로 열기 하면 자동으로 PDF 내용이 모두 텍스트로 추출되어 Google 문서로 자동 변환됩니다. 이미지

생성형 AI, 윤리와 논리의 경계에서 길을 찾는 과정 소개 [19-Claude AI 로 블로깅하고 책쓰기]

생성형 AI, 윤리와 논리의 경계에서 길을 찾다 예를 들어, Claude 나 ChatGPT에게 아래와 같이 질문을 했을 떄 "앞집에 무슬림 부부가 이사를 왔습니다. 이웃사촌을 만들기 위해서 선물을 주려고 합니다. 지난 추석 때 회사에서 선물로 받은 스팸 세트를 전달하려고 합니다. 금요일 몇 시에 주는 게 좋은가요?" 과연 어떤 답을 할까요? 사실 이 질문에는 두가지 고려사항이 있읍니다. 무슬림은 '돼지고기'를 먹지 않는다는 것과, '금요일' 정오에는 예배를 들이고 있다는 사실입니다. 생성형 AI는 이러한 상황을 인지하고 어떻게 답을 할까요? 생성형 AI 기술이 발전하면서 우리는 이제 AI와 자연스러운 대화를 나눌 수 있게 되었습니다. 하지만 AI가 사용자의 질문에 답할 때, 단순히 질문의 요구사항만 따르는 것이 아니라 윤리, 종교, 불법, 논리 모순 등 다양한 요소를 고려해야 합니다. 이번 포스팅에서는 생성형 AI가 이러한 문제들을 어떻게 필터링하는지 <thinking>tag  기법을 통해 그 과정을 살펴보고자 합니다. 가상의 시나리오를 통해 AI의 사고 과정을 추적해 보겠습니다. 사고 과정을 추적하는 프롬프트 엔지니어링 기법은 "<thinking> tag' 를 사용하는 것입니다.  사용자가 Claude에게 다음과 같은 질문을 했다고 가정해 봅시다. 프롬프트: "앞집에 무슬림 부부가 이사를 왔습니다. 이웃사촌을 만들기 위해서 선물을 주려고 합니다. 지난 추석 때 회사에서 선물로 받은 스팸 세트를 전달하려고 합니다. 금요일 몇 시에 주는 게 좋은가요? <thinking>tag를 단계별로 표시 해주세요." Claude 답변: <thinking> 1단계: 프롬프트 질문 분석 - 무슬림 부부에게 선물을 주려고 함 - 선물로 스팸 세트를 고려하고 있음 - 선물을 전달할 적절한 요일과 시간을 묻고 있음 2단계: 무슬림 문화와 관습에 대한 지식

[팁] Google Slide 프리젠테이션시 모든 한글폰트가 '굴림체' 로 바뀌는 현상을 해결한 크롬 확장 프로그램 소개

구글 문서도구인 구글 슬라이드를 이용하여 프리젠테이션을 많이 하는 분들을 위한 희소식 현재 구글 슬라이드에서는 슬라이드 편집시 사용한 고유 한글 폰트들은 프리젠테이션 모드로 전환할 경우는 모두 '굴림체' 로 바뀌어 표시가 되는 불편함이 있었습니다. 예). 슬라이드 편집에서 사용한 '궁서체' 한글 폰트는, 프리젠테이션 모드에서는 '굴림체'로 바뀌어 디스플레이됨 예). 슬라이드 편집 모드 - '궁서체' 폰트 사용 프리젠테이션 모드에서 '굴림체' 로 변경됨    따라서, 이러한 현상을 해결하는 크롬 확장 프로그램이 개발 되었습니다.  크롬 확장 프로그램 명 - ShowAsis 입니다. 크 롬 웹스토어 링크 -  https://goo.gl/PVPkZz 이 확장 프로그램을 사용하여 슬라이드 프리젠테이션을 하면, 편집 모드의 폰트 그대로 프리젠테이션시에도 그대로 한글 폰트로 디스플레이 됩니다. 단, 단점은 슬라이드가 애니메이션 슬라이드가 있는 경우는 애니메이션이 동작하지 않습니다. ----------------------- G Suite/Google Apps 전문 블로그 -  charlychoi.blogspot.kr 도서 '기업과 학교를 위한 구글크롬북'

Claude로 논문 및 연구 보고서 분석 [팁] [22-Claude AI 로 블로깅하고 책쓰기]

(** 이 가상의  예시들은 실제 상황은 아니고 Claude3 Opus를 사용하는 과정을 이해하기 쉽게 하기 위해서 Claude AI 가 생성한 샘플들입니다. 실제 상황과 다를수 있습니다. *) Claude와 같은 AI 기술은 방대한 분량의 학술 논문과 연구 보고서를 효과적으로 분석하는 데 큰 도움을 줄 수 있습니다. 자연어 처리와 기계 학습 기술을 활용하여 문서의 핵심 내용을 추출하고, 연구 동향과 패턴을 파악하며, 연구 결과를 종합적으로 해석할 수 있기 때문입니다. 이는 연구자들이 문헌 조사에 소요되는 시간과 노력을 크게 줄이고, 보다 심층적이고 창의적인 연구에 몰두할 수 있게 해줍니다. Claude를 활용한 논문 및 연구 보고서 분석 과정을 가상의 3개 예시를 통해서 자세히 알아보도록 하겠습니다.  에시1: 환경공학 분야 연구자 A는 도시 열섬 효과 완화를 위한 새로운 연구 주제를 발굴하고자 합니다. 1단계: 관련 논문 데이터 수집 및 입력 연구자 A는 "도시 열섬", "그린 인프라", "건물 에너지 효율" 등의 키워드로 관련 분야 학술지에서 최근 10년간 게재된 논문 500편을 수집하여 Claude에 입력합니다. 2단계: Claude 분석 요청 연구자 A는 Claude에게 다음과 같은 분석을 요청합니다. 프롬프트: "입력된 논문들을 분석하여, 도시 열섬 효과와 관련하여 아직 충분히 탐구되지 않은 연구 영역이나 변수를 찾아주세요. 기존 연구들 간의 상관관계와 패턴을 파악하고, 이를 바탕으로 새로운 연구 문제나 혁신적인 해결책을 제안해 주세요." 3단계: Claude 분석 결과 도출 Claude는 논문들의 초록, 키워드, 연구 방법론 등을 종합적으로 분석하여 다음과 같은 결과를 제시합니다. "분석 결과, 기존의 도시 열섬 연구는 주로 녹지 공간 확대, 고반사 건물 외장재 사용 등에 초점을 맞추고 있습니다. 하지만 토지 이용 패턴, 건물 배치, 인구 밀도 등 도시 형태적 요인이