발행일: 2026-10-06(화) 11:44
← 목차로 돌아가기|하루 30분 n8n 시리즈 ② 실무 자동화 레시피 100
RECIPE 021

소셜 미디어 예약 포스팅 자동화

  • ▸Google Sheets 데이터를 읽어 PDF 형식으로 변환할 수 있다
  • ▸Carbone 또는 HTML to PDF 방식으로 템플릿 기반 PDF를 생성할 수 있다
  • ▸생성된 PDF를 Gmail 첨부파일로 자동 발송할 수 있다

✅사전 준비

  • □Google Sheets 자격증명 연결 완료
  • □Gmail 자격증명 연결 완료
  • □HTML to PDF 변환 서비스 API 키 발급 (html2pdf.app 무료 플랜 가능)
  • □PDF로 만들 Sheets 시트 구조 확정 (예: 견적서 — 품목/수량/단가/합계)

Sheets 데이터 → HTML 조립 — Code 노드

const rows = $input.all();
const tableRows = rows.map(r =>
  `<tr><td>${r.json.품목}</td><td>${r.json.수량}</td><td>${r.json.단가?.toLocaleString()}원</td><td>${(r.json.수량 * r.json.단가)?.toLocaleString()}원</td></tr>`
).join('');

const total = rows.reduce((s, r) => s + r.json.수량 * r.json.단가, 0);

return [{ json: {
  html: `<!DOCTYPE html><html><body>
    <h2>견적서</h2>
    <p>발행일: ${new Date().toLocaleDateString('ko-KR')}</p>
    <table border='1' cellpadding='8' style='border-collapse:collapse;width:100%'>
      <thead><tr><th>품목</th><th>수량</th><th>단가</th><th>금액</th></tr></thead>
      <tbody>${tableRows}</tbody>
      <tfoot><tr><td colspan='3'><b>합계</b></td><td><b>${total.toLocaleString()}원</b></td></tr></tfoot>
    </table>
  </body></html>`,
  total
} }];

HTML → PDF 변환 — HTTP Request (html2pdf.app)

URL: https://api.html2pdf.app/v1/generate
Method: POST
Headers:
  Content-Type: application/json
Body (JSON):
  apiKey:  YOUR_API_KEY
  html:    {{ $json.html }}
  landscape: false
  paper:   A4

Gmail 첨부 발송 설정

To:          수신자이메일
Subject:     견적서_{{ $now.toFormat('yyyyMMdd') }}.pdf
Attachments: 이전 HTTP Request 바이너리 데이터 참조
File Name:   견적서_{{ $now.toFormat('yyyyMMdd') }}.pdf
💡 TIPhtml2pdf.app 무료 플랜은 월 50건 제한입니다. 더 많이 필요하면 puppeteer를 self-hosted n8n에서 직접 실행하거나 gotenberg 오픈소스를 Docker로 띄워 연결하세요.
⚡

워크플로우 JSON

아래 JSON을 복사해 n8n에 바로 임포트하세요

📥 n8n 임포트 방법
n8n 화면 우측 상단 메뉴 (⋮) → Import from JSON → 아래 JSON 전체 복사 후 붙여넣기 → Import 클릭
{
  "name": "recipe021_social_media_scheduled_posting",
  "nodes": [
    {
      "parameters": {
        "rule": {
          "interval": [
            {
              "field": "minutes",
              "minutesInterval": 30
            }
          ]
        }
      },
      "id": "schedule-021-01",
      "name": "30분마다 실행",
      "type": "n8n-nodes-base.scheduleTrigger",
      "typeVersion": 1.1,
      "position": [
        200,
        400
      ]
    },
    {
      "parameters": {
        "operation": "read",
        "documentId": {
          "value": "={{ $env.CONTENT_CALENDAR_SHEET_ID }}"
        },
        "sheetName": {
          "value": "schedule"
        },
        "options": {}
      },
      "id": "sheets-021-02",
      "name": "포스팅 일정표 조회",
      "type": "n8n-nodes-base.googleSheets",
      "typeVersion": 4.4,
      "position": [
        420,
        400
      ]
    },
    {
      "parameters": {
        "jsCode": "const now = new Date();\nconst items = $input.all();\nconst toPost = items.filter(item => {\n  const scheduled = new Date(item.json.scheduledAt);\n  const diffMin = (now - scheduled) / 60000;\n  return item.json.status === '예정' && diffMin >= 0 && diffMin <= 30;\n});\nreturn toPost.map(i => ({ json: i.json }));"
      },
      "id": "code-021-03",
      "name": "지금 발행할 항목 필터링",
      "type": "n8n-nodes-base.code",
      "typeVersion": 2,
      "position": [
        640,
        400
      ]
    },
    {
      "parameters": {
        "method": "POST",
        "url": "https://api.bufferapp.com/1/updates/create.json",
        "authentication": "genericCredentialType",
        "genericAuthType": "httpHeaderAuth",
        "sendBody": true,
        "bodyParameters": {
          "parameters": [
            {
              "name": "text",
              "value": "={{ $json.content }}"
            },
            {
              "name": "profile_ids[]",
              "value": "={{ $env.BUFFER_PROFILE_ID }}"
            }
          ]
        },
        "options": {}
      },
      "id": "http-021-04",
      "name": "Buffer로 SNS 발행",
      "type": "n8n-nodes-base.httpRequest",
      "typeVersion": 4.2,
      "position": [
        860,
        400
      ]
    },
    {
      "parameters": {
        "operation": "update",
        "documentId": {
          "value": "={{ $env.CONTENT_CALENDAR_SHEET_ID }}"
        },
        "sheetName": {
          "value": "schedule"
        },
        "columns": {
          "mappingMode": "defineBelow",
          "value": {
            "status": "완료",
            "postedAt": "={{ $now.format('YYYY-MM-DD HH:mm') }}"
          }
        },
        "options": {}
      },
      "id": "sheets-021-05",
      "name": "발행 완료 상태 업데이트",
      "type": "n8n-nodes-base.googleSheets",
      "typeVersion": 4.4,
      "position": [
        1080,
        400
      ]
    }
  ],
  "connections": {
    "30분마다 실행": {
      "main": [
        [
          {
            "node": "포스팅 일정표 조회",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "포스팅 일정표 조회": {
      "main": [
        [
          {
            "node": "지금 발행할 항목 필터링",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "지금 발행할 항목 필터링": {
      "main": [
        [
          {
            "node": "Buffer로 SNS 발행",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Buffer로 SNS 발행": {
      "main": [
        [
          {
            "node": "발행 완료 상태 업데이트",
            "type": "main",
            "index": 0
          }
        ]
      ]
    }
  },
  "settings": {
    "timezone": "Asia/Seoul"
  },
  "meta": {
    "chapter": 2,
    "recipe": "021",
    "title": "소셜 미디어 예약 포스팅 자동화",
    "difficulty": "⭐⭐",
    "estimatedTime": "30분",
    "apps": [
      "Google Sheets",
      "Buffer"
    ]
  }
}
← 이전 레시피☰ 목차다음 레시피 →