# 내 웨딩 웹사이트에 만드는 결혼식 RSVP 폼

> 직접 만든 웨딩 웹사이트용 RSVP 폼: 초대장당 응답 하나, 이름이 있는 손님별 식사, 마감일, 아직 응답하지 않은 사람 목록.

2026-10-25 게시 · https://ikiform.com/ko/guides/event-registration/wedding-rsvp

초대장마다 초대 코드와 손님 이름을 담은 RSVP 링크를 주고, 폼이 손님마다 이름과 식사 선택을 하나씩 보여 주게 하세요. 모든 응답은 Ikiform으로 POST되므로 응답마다 이메일을 받고, 케이터링 업체에 넘길 CSV도 생깁니다. 스프레드시트에서 응답을 하객 명단과 맞춰 보면 누가 아직 응답하지 않았는지 알 수 있고, 마감일이 지나면 폼을 일시 중지하세요.

## 결혼식은 무엇이 다른가

밋업은 모르는 사람을 셉니다. 결혼식은 이미 가진 하객 명단을 초대장 단위로 셉니다. 여기서 네 가지가 따라옵니다.

- **사람이 아니라 초대장당 응답 하나.** 부부나 가족은 함께 응답합니다.
- **손님 수가 아니라 이름이 있는 손님.** `2`가 아니라 Ada와 Sam을 초대했습니다. 동반자는 초대장에 있거나 없거나 둘 중 하나입니다.
- **사람마다 식사 하나.** 케이터링 업체는 생선, 소고기, 채식 합계와 어린이 메뉴 수가 필요합니다.
- **확실한 마감일과 연락할 명단.** 행사장은 날짜까지 인원을 원하고, 유용한 명단은 아직 응답하지 않은 사람들입니다.

Zola, The Knot, Joy 같은 웨딩 웹사이트 서비스에는 하객 명단을 중심으로 이름으로 찾는 RSVP 도구가 있습니다. 그런 서비스로 사이트를 만들었다면 그 RSVP를 쓰세요. 이 페이지는 Squarespace, Carrd, Framer, 일반 HTML로 직접 만든 웨딩 사이트에서 RSVP를 내 페이지에 두고 싶은 경우를 위한 것입니다.

Ikiform에는 하객 명단 조회와 반복 그룹이 없으므로, 폼 스스로는 초대장에 누가 있는지 알 수 없습니다. 비결은 그 정보를 링크에 담는 것입니다.

다이어그램: 하객 명단에서 케이터링 수량까지, 개인 RSVP 링크로

1. 하객 명단 시트에는 초대장마다 한 행이 있습니다. 짧은 코드, 가족 이름, 손님 이름입니다.
2. 수식이 각 행을 코드와 이름을 담은 개인 RSVP 링크로 바꿉니다.
3. 링크를 초대장에 QR 코드로 인쇄하거나 메시지로 보냅니다.
4. RSVP 페이지가 링크를 읽고 손님마다 이름과 식사 선택을 하나씩 보여 준 뒤, Ikiform으로 POST합니다.
5. 응답을 CSV로 내보내 하객 명단 옆에 가져옵니다.
6. 코드를 맞춰 보면 어떤 초대장이 응답하지 않았는지 보이므로, 누구에게 연락할지 알 수 있습니다.
7. 응답 전체에서 식사별로 세면 케이터링 업체에 줄 합계가 나옵니다.

하객 명단은 시트에 남습니다. 링크에는 폼을 개인화할 만큼만 담깁니다.

## 초대장마다 링크 만들기

하객 명단 시트의 A열에 `okafor`나 `nguyen-family` 같은 짧은 코드를, B열에 가족 이름을, C열에 손님들의 이름을 쉼표로 구분해 넣으세요. D열의 이 수식이 링크를 만듭니다.

`하객 명단, D열`:

```text
="https://ada-and-sam.example/rsvp?party=" & A2 & "&names=" & ENCODEURL(C2)
```

각 링크를 초대장에 QR 코드로 인쇄하거나 메시지에 붙여 넣으세요. 코드는 소문자와 하이픈으로만 만드세요. 필드의 패턴이 다른 것은 거부하므로 잘못 입력한 코드를 일찍 잡아냅니다.

## 폼

이 코드를 웨딩 페이지나 빌더의 임베드 블록에 붙여 넣으세요. 링크에서 `party`와 `names`를 읽어 손님마다 이름과 식사 행을 최대 4개까지 추가하고, 마감일이 지나면 스스로 숨겨집니다. 링크에 이름이 없으면 직접 채울 행 하나를 보여 줍니다.

`rsvp.html`:

```html
<form id="rsvp" action="https://ikiform.com/f/frm_xxxxxxxxxxxxxxxx" method="post">
  <input type="hidden" name="party" id="party">
  <div id="guests"></div>
  <label>Email for updates <input name="email" type="email" autocomplete="email" required></label>
  <label>A song that gets you dancing <input name="song" maxlength="120"></label>
  <label>Anything we should know? <textarea name="note" rows="3" maxlength="1000"></textarea></label>
  <input type="hidden" name="_redirect" value="https://ada-and-sam.example/thank-you">
  <input name="_gotcha" type="text" tabindex="-1" autocomplete="off" hidden>
  <button type="submit">Send our RSVP</button>
</form>
<p id="closed" hidden>RSVPs closed on 1 May. Message us if your plans have changed.</p>

<template id="guest-row">
  <fieldset>
    <legend></legend>
    <label>Name <input data-part="name" maxlength="80" autocomplete="off"></label>
    <label>Meal
      <select data-part="meal">
        <option value="beef">Beef</option>
        <option value="fish">Fish</option>
        <option value="vegetarian">Vegetarian</option>
        <option value="child">Child's menu</option>
        <option value="not_coming">Can't come</option>
      </select>
    </label>
  </fieldset>
</template>

<script>
  const DEADLINE = new Date("2027-05-01T23:59:00+01:00");
  const params = new URLSearchParams(location.search);
  const party = (params.get("party") ?? "").toLowerCase();
  const names = (params.get("names") ?? "").split(",").map((name) => name.trim()).filter(Boolean).slice(0, 4);
  const rsvp = document.getElementById("rsvp");

  if (Date.now() > DEADLINE.getTime()) {
    rsvp.hidden = true;
    document.getElementById("closed").hidden = false;
  } else {
    document.getElementById("party").value = party;
    const rows = names.length ? names : [""];
    rows.forEach((name, index) => {
      const n = index + 1;
      const row = document.getElementById("guest-row").content.cloneNode(true);
      row.querySelector("legend").textContent = name || "Your name";
      const input = row.querySelector('[data-part="name"]');
      input.name = `guest_${n}_name`;
      input.value = name;
      input.required = n === 1;
      row.querySelector('[data-part="meal"]').name = `guest_${n}_meal`;
      document.getElementById("guests").append(row);
    });
  }
</script>
```

- 손님별 식사에는 `Can't come`이 있으므로, 한 사람이 올 수 없는 가족도 응답 하나로 보낼 수 있습니다.
- 이름 입력은 미리 채워져 있지만 수정할 수 있으므로, 손님이 철자를 고치거나 아이 이름을 적을 수 있습니다.
- 폼은 일반적인 방식으로 POST하고 `_redirect`를 통해 여러분의 감사 페이지로 이동합니다. 거기에 날짜, 장소, 캘린더 링크를 넣으세요. Ikiform은 하객에게 이메일을 보내지 않습니다.
- 마감일은 브라우저에서 폼을 숨길 뿐입니다. 마감일에는 Ikiform에서도 **Pause form**을 골라, 저장해 둔 탭에서 POST할 수 없게 하세요. 일시 중지된 폼은 `403 form_paused`로 응답합니다.

이 정의를 폼의 **Fields** 탭에 붙여 넣으세요. 직접 해 보세요. 대문자나 공백이 들어간 초대 코드는 패턴에 걸리고, 설정한 메시지가 표시됩니다.

폼: Wedding RSVP

- **초대 코드** (`party`, text, 필수)
- **소식 받을 이메일** (`email`, email, 필수)
- **손님 1 이름** (`guest_1_name`, text, 필수)
- **손님 1 식사** (`guest_1_meal`, select, 필수)
- **손님 2 이름** (`guest_2_name`, text)
- **손님 2 식사** (`guest_2_meal`, select)
- **손님 3 이름** (`guest_3_name`, text)
- **손님 3 식사** (`guest_3_meal`, select)
- **손님 4 이름** (`guest_4_name`, text)
- **손님 4 식사** (`guest_4_meal`, select)
- **춤추고 싶어지는 노래** (`song`, text)
- **저희가 알아야 할 것이 있나요?** (`note`, textarea)

필드는 초대장 순서대로라서 CSV에서 각 손님의 이름 다음에 식사가 옵니다. 첫 번째 손님만 필수입니다.

## 누가 응답하지 않았는지, 무엇을 주문할지

1. **Submissions**에서 RSVP를 CSV로 내보내 하객 명단 스프레드시트의 `Replies` 탭으로 가져오세요.
2. 초대장 하나가 두 번 응답했다면 최신 행을 남기세요. `created_at` 기준 최신순으로 정렬하고 `party` 열에서 중복을 제거하면 됩니다.
3. 하객 명단의 A열에 코드가, Replies의 E열에 `party`가 있을 때 응답하지 않은 초대장을 나열합니다.

`미응답`:

```text
=FILTER(A2:C, A2:A <> "", ISNA(MATCH(A2:A, Replies!E2:E, 0)))
```

그다음 케이터링 업체를 위해 식사별로 세세요. 이름이 식사 값과 같을 일은 없으므로 모든 손님 열을 아우르는 범위 하나로 충분합니다.

`생선 요리 수`:

```text
=COUNTIF(Replies!G2:N, "fish")
```

| 숫자 | 방법 |
| --- | --- |
| 참석 인원 | `beef`, `fish`, `vegetarian`, `child` 개수를 더합니다 |
| 참석 불가 | 같은 범위에서 `not_coming`을 `COUNTIF`합니다 |
| 어린이 메뉴 수 | `child`를 `COUNTIF`합니다. 대부분의 케이터링 업체는 따로 가격을 매깁니다 |
| 식이 관련 메모 | `note` 열을 읽으세요. 알레르기 정보가 여기에 숨어 있습니다 |

> 알림 이메일은 각 손님의 이메일을 회신 주소로 해서 도착하므로, 받은편지함에서 바로 질문에 답할 수 있습니다. Ikiform은 하객이 아니라 여러분과 배우자에게 이메일을 보냅니다.

## 초대장을 보내기 전에

- **Allowed domains**를 웨딩 사이트의 도메인으로 설정하고, 테스트하는 동안에는 빌더의 스테이징 도메인도 추가하세요.
- Ikiform은 이메일 기준으로 반복 제출을 합치거나 거부하지 않습니다. 24시간 안에 똑같은 제출이 반복되면 스팸 점수만 올라갑니다. 명단을 보관하는 곳이나 내보낼 때 중복을 제거하세요. 코드별 최신 응답이 정답입니다.
- 링크를 가진 사람은 누구나 코드나 이름을 바꿀 수 있습니다. 결혼식에는 괜찮습니다. 누구를 초대했는지는 시트가 정하고, 미응답 목록에서 이상한 점이 드러납니다.
- 나이 드신 친척은 폼을 아예 쓰지 않을 수도 있습니다. 전화나 종이로 받은 응답도 시트에 적어 두면 집계가 완전하게 유지됩니다.

## 초대장을 보내기 전에 확인하기

1. 휴대폰에서 내 초대 링크를 열어 보세요. 이름이 각각 식사 선택과 함께 표시됩니다.
2. 한 손님에게 `Can't come`을 고르고 보낸 뒤 감사 페이지로 이동하는지 확인하세요.
3. 대시보드에서 **Submissions**를 여세요. 보낸 모든 필드가 담긴 새 제출이 있습니다.
4. 알림 수신자 각각의 받은편지함을 확인하세요. 각자 필드가 담긴 이메일을 받고, 폼에 `email` 필드가 있으면 **Reply**는 제출자에게 갑니다.
5. CSV를 가져와서 미응답 목록에 더 이상 내 코드가 없는지 확인하세요.
6. 테스트용 사본에서 마감일을 어제로 설정하고 폼이 숨겨지는지 확인하세요.

## 주의할 점

| 문제 | 해결 방법 |
| --- | --- |
| `party: Use the link from your invitation`과 함께 `422` | 코드에 대문자, 공백, 기타 문자가 들어 있습니다. 시트에서 코드를 고치거나 손님에게 자신의 링크를 쓰게 하세요. |
| 손님에게 이름 대신 빈 행 하나가 보입니다 | 링크에서 `names` 부분이 빠졌습니다. 메신저 앱이 링크를 줄였을 때 자주 생깁니다. 전체 링크나 QR 코드를 보내세요. |
| `422 validation_failed` | POST가 폼의 필드 정의와 맞지 않습니다. `error.fields`에 각 필드와 이유가 나옵니다. 입력의 `name`을 필드 ID와 맞추세요. |
| `403 origin_not_allowed`, 또는 모든 POST가 스팸으로 분류됨 | 페이지의 도메인이 폼의 **Allowed domains**에 없습니다. 도메인을 추가하고, 로컬 테스트용으로 `localhost`도 추가하세요. 등록된 도메인의 하위 도메인은 허용됩니다. |
| 브라우저가 내 페이지가 아니라 Ikiform의 감사 페이지로 이동합니다 | `_redirect`는 도메인이 **Allowed domains**에 있고 `https:` URL일 때만 따릅니다. 도메인을 추가하거나, 대신 폼 설정에서 **Redirect after submit**을 설정하세요. |

## 질문

### 손님이 다른 참석자를 볼 수 있나요?

아니요. RSVP는 Ikiform 대시보드와 여러분의 받은편지함으로 갑니다. 사이트에 다시 게시되는 것은 없습니다.

### 폼이 손님에게 확인 이메일을 보낼 수 있나요?

Ikiform에서는 안 됩니다. Ikiform은 여러분에게만 이메일을 보냅니다. 감사 페이지에 세부 정보를 보여 주거나, 각 응답을 웹훅으로 이메일 도구에 보내 거기서 확인 이메일을 발송하세요.

### 마감일 이후에는 RSVP를 어떻게 막나요?

예제처럼 날짜가 지나면 페이지에서 폼을 숨기고, Ikiform에서 Pause form을 고르세요. 일시 중지된 폼은 새 POST를 403 form_paused로 거부합니다.

### 손님이 두 번 응답하면 어떻게 되나요?

두 응답 모두 저장됩니다. 집계할 때 최신순으로 정렬하고 코드에서 중복을 제거해 초대 코드별 최신 응답만 남기세요.

### Ikiform은 무료인가요?

아니요, 무료 플랜은 없습니다. 테스트는 무료입니다. 결제 전에 localhost에서 테스트 제출을 매월 50건 보낼 수 있습니다. 실제로 운영하려면 Pro가 제출 500건에 월 $6부터이며, 한 번만 결제해 제출 10,000건을 $49에, 50,000건을 $149에 살 수도 있습니다. 크레딧은 만료되지 않습니다.

## 가이드 더 보기

- [행사 등록](https://ikiform.com/ko/guides/event-registration.md): 티켓 앱 없이 내 행사 페이지에서 RSVP를 받는 방법: 폼, 동반 인원 제한, 정확한 인원 집계, 마감, 체크인 명단.
- [Eventbrite 없이](https://ikiform.com/ko/guides/event-registration/without-eventbrite.md): 무료 커뮤니티 행사의 등록을 내 사이트에서 운영하세요: 세션 선택, 내 도구로 보내는 확인 이메일, 강의실별 인원, 체크인 명단.
- [자원봉사자 신청](https://ikiform.com/ko/guides/event-registration/volunteer-signup.md): 사람들이 근무 시간을 고르고 당일 연락처를 남기는 자원봉사자 신청 폼과, 인원이 부족한 근무 시간을 보여 주고 근무표를 만드는 스크립트.
