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: A4Gmail 첨부 발송 설정
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 클릭
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"
]
}
}