개인 비서형 AI 에이전트, 실제로 일을 맡기면 누가 제일 잘할까요? AI 팟캐스트 How I AI의 진행자가 'How I AI Personal Agent Bench'라는 비교 테스트를 공개했습니다. Grok Bot, Muse, ChatGPT Dot, Claude Duet 네 에이전트에게 아홉 가지 과제를 맡겨 비교했고, 진행자는 Grok Bot이 1위라고 발표했습니다. 이 글은 리서처K 숏폼 영상의 글 버전입니다. 숏폼으로 보기 ▲ 이미지를 누르면 유튜브 숏폼으로 이동합니다: https://youtube.com/shorts/T_30By0-M0g 어떤 비교였나 비교 대상: Grok Bot, Muse, ChatGPT Dot, Claude Duet 과제: Slack 답장 쓰기, 숏폼 클립 만들기, 버그 수정, 썸네일 만들기, 받은편지함 할 일 정리, 가족 신문 만들기, 숙제 설명, 신발 쇼핑, 출시 영상 만들기 등 아홉 가지 진행 방식: 진행자가 평소처럼 짧은 프롬프트를 주고, 방송 중에 직접 결과를 평가했습니다. 블라인드 평가는 아니었습니다. 진행자가 발표한 결과 순위: Grok Bot 1위, Muse 2위, ChatGPT Dot 3위, Claude Duet 4위 점수: 본편에서 Grok Bot은 93%, Claude Duet은 79%로 소개됐습니다. Grok Bot이 이긴 과제: 썸네일 만들기, 받은편지함 할 일 정리, 신발 쇼핑 진행자의 정리: 업무 일은 Grok Bot, 생활 일은 Muse에게 맡기라고 권했습니다. 진행자는 X 게시물에서 Grok Bot이 "큰 차이로(by A LOT)" 이겼다고 표현했습니다. 다만 공개된 수치로 확인되는 차이는 1위와 4위 사이의 14%p이고, Muse와 Dot의 퍼센트 점수는 공개 자료에서 확인되지 않았습니다. 짚고 갈 점 이 결과는 진행자 한 사람이 직접 진행한 비교이며, 공인된 표준 벤...
지메일이 좋은 이유는, 지메일에서 제공하는 기본적인 기능외에도 사용자들이 필요로하는 유용한 기능들을 직접 추가할 수 있는 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 아이콘이 보여야 합니다.
편지쓰기시 하단에 ‘Send Later’ 라는 버튼이 보입니다. 이 버튼을 클릭하여 예약을 원하는 날짜및 시간을 입력하여 전송 하면 됩니다.
자세한 사항은 구글문서 참조
댓글
댓글 쓰기