매일 아침 정책브리팅 (메일 발송 단계)

소개

중기부 보도자료 api를 이용해 수집된 신규등록 보도자료를 이메일로 받기 위한 마지막 단계를 진행함.

이전 과정을 통해 구글시트에 새로 등록된 전일자 보도자료를 지메일로 발송하는 부분은 생각보다 간단하게 진행됨

원래 make를 이용할 생각이었으나 이전글 댓글에서 스크립트로 간단하게 가능한 부분이라는 조언 덕분에 편하게 진행하게 되었음.(감사합니다^^)

진행 방법

클로드에 비교적 간단한 프롬프트를 통해 메일 발송 스크립트를 작성함.

한국어로 된 문자 메시지의 스크린샷
한국어 텍스트가 있는 검은 화면
한국어 텍스트가 있는 검은 화면

코드는 초기화 부분과 메일 발송으로 나뉘는데, 초기화는 구글시트의 현재상태를 먼저 정의하기 위한 과정임. 트리거는 시트 수정 기준이라 초기화 상태이후 새로 추가되는 데이터가 발생하면 메일발송 코드가 작동됨.

// 마지막으로 처리된 행을 저장할 프로퍼티
const LAST_PROCESSED_ROW_KEY = 'LAST_PROCESSED_ROW';

// 새로운 데이터 확인 및 이메일 발송
function checkNewDataAndSendEmail() {
  // 스프레드시트 열기
  const spreadsheetId = '1dPdk9ItxPY9hF1JJeDZ43y3JGHVN8KFGInWjbrlrUxI';
  const sheet = SpreadsheetApp.openById(spreadsheetId).getSheetByName('보도자료');
  
  // 데이터 범위 가져오기
  const data = sheet.getDataRange().getValues();
  
  // 헤더 행을 찾기
  const headers = data[0];
  const titleColIndex = headers.indexOf('제목');
  const linkColIndex = headers.indexOf('링크');
  
  // 프로퍼티 서비스에서 마지막으로 처리된 행 번호 가져오기
  const userProperties = PropertiesService.getUserProperties();
  let lastProcessedRow = parseInt(userProperties.getProperty(LAST_PROCESSED_ROW_KEY)) || 1;
  
  // 새로운 데이터 확인
  const currentLastRow = data.length;
  const newRows = [];
  
  // 마지막으로 처리된 행 이후의 새로운 데이터 수집
  if (currentLastRow > lastProcessedRow) {
    for (let i = lastProcessedRow; i < currentLastRow; i++) {
      const row = data[i];
      if (row[titleColIndex]) { // 제목이 있는 행만 처리
        // 해당 셀의 하이퍼링크 가져오기
        const titleCell = sheet.getRange(i + 1, titleColIndex + 1);
        const titleLink = titleCell.getRichTextValue()?.getLinkUrl() || row[linkColIndex] || '';
        
        newRows.push({
          title: row[titleColIndex],
          titleLink: titleLink,
          link: row[linkColIndex]
        });
      }
    }
    
    // 새로운 데이터가 있으면 이메일 발송
    if (newRows.length > 0) {
      // 메일 내용 구성
      let emailBody = '중소기업벤처부 신규 보도자료\n\n';
      newRows.forEach((row, index) => {
        emailBody += `(${index + 1}) ${row.title}\n`;
        // 제목 링크가 있으면 추가
        if (row.titleLink) {
          emailBody += `제목링크: ${row.titleLink}\n`;
        }
        // 기존 링크가 있고 제목 링크와 다른 경우에만 추가
        if (row.link && row.link !== row.titleLink) {
          emailBody += `링크: ${row.link}\n`;
        }
        emailBody += '\n';
      });
      
      // 메일 발송
      MailApp.sendEmail({
        to: Session.getActiveUser().getEmail(),
        subject: `중소기업벤처부 신규 보도자료 (${new Date().toLocaleDateString()})`,
        body: emailBody
      });
      
      // 마지막으로 처리된 행 번호 업데이트
      userProperties.setProperty(LAST_PROCESSED_ROW_KEY, currentLastRow.toString());
    }
  }
}

// 초기 설정 함수
function initialize() {
  // 기존의 트리거 모두 삭제
  const triggers = ScriptApp.getProjectTriggers();
  triggers.forEach(trigger => ScriptApp.deleteTrigger(trigger));
  
  // 새로운 트리거 생성 - 스프레드시트가 수정될 때마다 실행
  ScriptApp.newTrigger('checkNewDataAndSendEmail')
    .forSpreadsheet(SpreadsheetApp.openById('1dPdk9ItxPY9hF1JJeDZ43y3JGHVN8KFGInWjbrlrUxI'))
    .onEdit()
    .create();
  
  // 주기적 체크를 위한 시간 기반 트리거도 추가 (5분마다)
  ScriptApp.newTrigger('checkNewDataAndSendEmail')
    .timeBased()
    .everyMinutes(5)
    .create();
    
  // 마지막 처리 행 초기화
  const sheet = SpreadsheetApp.openById('1dPdk9ItxPY9hF1JJeDZ43y3JGHVN8KFGInWjbrlrUxI').getSheetByName('보도자료');
  const lastRow = sheet.getLastRow();
  PropertiesService.getUserProperties().setProperty(LAST_PROCESSED_ROW_KEY, lastRow.toString());
}

// 수동으로 마지막 처리 행 초기화
function resetLastProcessedRow() {
  PropertiesService.getUserProperties().setProperty(LAST_PROCESSED_ROW_KEY, '1');
}

단, 당초 작성된 스크래핑하는 스크립트에 추가하여 코드를 저장했을 경우 테스트 메일은 가능한데 정작 아침에 보면 메일 발송이 안됨. 메일발송 초기하함수에 기존 트리거 제거 부분이 영향을 미친 것으로 판단됨.

며칠 테스트 해보다가 혹사나 하고 메일 발송 함수를 별도의 스크립트로 작성해봄.

한자가 포함된 Google 검색 페이지의 스크린샷

오늘 아침 이메일이 정상적으로 발송되어 확인하였음.

결과와 배운 점

다소 간단한 자동화 과정이지만 처음 도전하는 입장이라 다양한 시행착오를 경험하였습니다.

여러 사례글과 선배분들의 경험담을 통해 다양한 시각과 접근방법을 알게 되어 많이 감사한 마음을 전합니다.

앞으로도 기회가 된다면 함께 공부하면서 성장하고 싶은 초보의 간단 사례글 마치겠습니다.

1
1개의 답글

👉 이 게시글도 읽어보세요