디스코드 봇 만들기

디스코드 임베드(Embed) 완전정복 - 메시지 꾸미기 메서드·제한값 총정리 (discord.py 2.x) 📋

Mojangcam 2026. 7. 26. 10:59

안녕하세요! Mojangcam입니다 😎

디스코드 봇을 만들다 보면 꼭 만나는 벽이 하나 있어요. "봇이 보내는 메시지가 너무 밋밋한데요?"

그냥 텍스트로 이벤트 안내: 7월 1일 ~ 7월 31일 이렇게 보내면 아무도 안 읽어요. 그런데 색깔 띠가 붙고, 제목이 굵게 나오고, 이미지랑 표처럼 정리된 항목이 들어간 임베드(Embed)로 보내면 완전히 달라집니다. 서버 공지, 유저 프로필 카드, 음악 봇 재생목록, 에러 리포트 — 우리가 예쁘다고 생각하는 봇 메시지는 사실상 전부 임베드예요.

지난 디스코드 봇 만들기 #8 - 임베드 이미지·필드로 꾸미기에서 기본기를 다뤘다면, 오늘은 임베드 하나만 파고드는 레퍼런스 글이에요. 메서드 전체 목록, 글자 수 제한값, 색상 지정법, 자주 나는 에러까지 이 글 하나로 끝내볼게요. 북마크 해두고 필요할 때 꺼내 쓰기 좋게 표로 정리했습니다! 🙌

📌 준비물

  • Python 3.8 이상 (discord.py 공식 요구사항, 3.7 이하는 미지원)
  • discord.py 2.7.1 (2026년 7월 기준 최신 안정 버전)
  • 디스코드 개발자 포털에서 발급한 봇 토큰
pip install -U discord.py

설치된 버전이 궁금하면 이렇게 확인해요.

python -c "import discord; print(discord.__version__)"
⚠️ 이 글의 코드는 전부 discord.py 2.x 기준이에요. 1.x 시절 코드는 문법이 꽤 달라서 그대로 쓰면 에러가 납니다. 특히 Embed.Empty는 2.0에서 삭제됐어요 (뒤에서 자세히 설명할게요).

🧩 임베드는 어떤 구조인가요?

임베드는 레고 블록처럼 정해진 자리가 있어요. 아무 데나 텍스트를 넣는 게 아니라, 자리마다 이름이 정해져 있습니다.

자리 무엇이 들어가나요 지정 방법
author 맨 위 작은 이름 + 아이콘 set_author()
title 큰 제목 (링크 걸 수 있음) Embed(title=..., url=...)
description 제목 아래 본문 Embed(description=...)
fields 항목별 소제목 + 내용 (최대 25개) add_field()
thumbnail 오른쪽 위 작은 이미지 set_thumbnail()
image 아래쪽 큰 이미지 set_image()
footer 맨 아래 작은 글씨 + 아이콘 set_footer()
timestamp footer 옆 시간 표시 Embed(timestamp=...)
colour 왼쪽 세로 색깔 띠 Embed(colour=...)

📌 1단계 - 가장 기본 임베드 보내기

먼저 뼈대부터요. 제목·본문·색깔 세 개만 넣어도 훨씬 그럴싸해집니다.

import discord

embed = discord.Embed(
    title="🎉 7월 이벤트 안내",
    description="이번 달 출석 이벤트가 시작됐어요!\n아래 내용을 확인해주세요.",
    colour=discord.Colour.blurple(),
)

await interaction.response.send_message(embed=embed)

하나씩 뜯어볼게요 💡

  • title : 임베드 큰 제목. 최대 256자예요.
  • description : 제목 아래 본문. 최대 4096자로 가장 넉넉합니다. \n으로 줄바꿈되고 마크다운(**굵게**, `코드`)도 먹혀요.
  • colour : 왼쪽 세로 띠 색깔. color로 써도 똑같이 동작합니다 (완전한 별칭이에요).
  • embed= : 메시지를 보낼 때 content 대신 embed 인자로 넘겨요. 둘을 같이 넘겨서 "일반 텍스트 + 임베드"도 됩니다.
💡 discord.Embed의 인자는 전부 키워드 전용이에요. discord.Embed("제목")처럼 위치 인자로 넣으면 TypeError가 납니다. 꼭 title="제목" 형태로 쓰세요.

📌 2단계 - 필드(Field)로 항목 정리하기

임베드가 진짜 강해지는 지점이 여기예요. 필드는 소제목 + 내용 한 쌍이고, inline으로 가로 배치까지 정할 수 있어요.

embed.add_field(name="📅 기간", value="7월 1일 ~ 7월 31일", inline=True)
embed.add_field(name="🎁 보상", value="닉네임 색상 역할", inline=True)
embed.add_field(name="📌 참여 방법", value="`/출석` 명령어를 매일 입력하세요.", inline=False)

하나씩 뜯어볼게요 💡

  • name : 필드 소제목. 최대 256자. 굵게 표시돼요.
  • value : 필드 내용. 최대 1024자. 여기도 마크다운이 먹힙니다.
  • inline : True면 옆 필드와 가로로 나란히(한 줄에 최대 3개), False한 줄 통째로 차지해요. 기본값은 True입니다.
  • 필드는 임베드당 최대 25개까지만 들어가요.

그리고 add_field()자기 자신을 반환해서 이렇게 체이닝도 됩니다.

embed = (
    discord.Embed(title="서버 규칙", colour=discord.Colour.green())
    .add_field(name="1️⃣", value="욕설 금지", inline=False)
    .add_field(name="2️⃣", value="광고 금지", inline=False)
    .set_footer(text="위반 시 경고 3회 → 밴")
)

필드를 나중에 손대야 할 때는 이 네 개를 씁니다.

메서드 하는 일
insert_field_at(index, *, name, value, inline=True) 특정 위치에 끼워넣기
set_field_at(index, *, name, value, inline=True) 특정 위치를 덮어쓰기 (없는 인덱스면 IndexError)
remove_field(index) 하나 삭제
clear_fields() 전부 삭제
⚠️ index만 위치 인자이고 name·value·inline은 키워드 전용이에요. set_field_at(0, "제목", "내용")은 에러입니다.

📌 3단계 - 이미지·작성자·푸터로 마무리 꾸미기

embed.set_author(name="Mojangcam 봇", icon_url=client.user.display_avatar.url)
embed.set_thumbnail(url="https://example.com/thumb.png")
embed.set_image(url="https://example.com/banner.png")
embed.set_footer(text="문의는 /문의 명령어로", icon_url="https://example.com/icon.png")

하나씩 뜯어볼게요 💡

  • set_author(*, name, url=None, icon_url=None) : 맨 위 작은 이름줄. name필수, 최대 256자. url을 주면 이름이 링크가 돼요.
  • set_thumbnail(*, url) : 오른쪽 위 작은 이미지. 프로필 사진·아이템 아이콘에 잘 어울려요.
  • set_image(*, url) : 아래쪽 이미지(배너). 가로로 꽉 찹니다.
  • set_footer(*, text=None, icon_url=None) : 맨 아래 작은 글씨. text는 최대 2048자.
  • 지우고 싶으면 url=None / text=None을 넘기거나 remove_author()·remove_footer()를 쓰면 돼요.
💡 set_imageset_thumbnailurl키워드 전용이면서 기본값이 없는 필수 인자예요. set_image("주소")처럼 쓰면 TypeError가 납니다. 꼭 set_image(url="주소")로!

📌 임베드 메서드 총정리 (치트시트)

검색해서 이 글에 온 분들을 위해 한 표에 몰아넣었어요. discord.py 2.7.1 기준입니다.

메서드 시그니처 설명
생성자 Embed(*, colour=None, color=None, title=None, type='rich', url=None, description=None, timestamp=None) 전부 키워드 전용
add_field (*, name, value, inline=True) 필드 추가 (최대 25개)
insert_field_at (index, *, name, value, inline=True) 지정 위치에 삽입
set_field_at (index, *, name, value, inline=True) 지정 위치 교체
remove_field (index) 필드 삭제
clear_fields () 필드 전체 삭제
set_author (*, name, url=None, icon_url=None) 상단 작성자
remove_author () 작성자 제거
set_footer (*, text=None, icon_url=None) 하단 푸터
remove_footer () 푸터 제거
set_image (*, url) 큰 이미지
set_thumbnail (*, url) 작은 썸네일
to_dict () dict로 변환 (저장용)
from_dict (data) dict → 임베드 (클래스메서드)
copy () 임베드 복사
len(embed) 글자 수 합계 반환

위 메서드들은 전부 자기 자신을 반환해서 점(.)으로 계속 이어 쓸 수 있어요.

📌 임베드 제한값 총정리 (이거 넘으면 400 에러!)

디스코드 공식 문서 기준 제한값이에요. 봇이 갑자기 Bad Request를 뱉는다면 십중팔구 여기 걸린 겁니다.

항목 최대값
title 256자
description 4096자
fields 개수 25개
field.name 256자
field.value 1024자
footer.text 2048자
author.name 256자
메시지 하나당 임베드 개수 10개
메시지 내 전체 임베드 글자 합계 6000자

마지막 6000자가 함정이에요. 임베드 하나당이 아니라 메시지에 붙은 모든 임베드를 합쳐서 6000자입니다. 임베드 3개를 한 번에 보낼 거면 3개 합계로 계산해야 해요.

그래서 미리 체크하는 습관이 중요합니다.

if len(embed) > 6000:
    await interaction.response.send_message("내용이 너무 길어요! 나눠서 보낼게요.")
    return

len(embed)title + description + 모든 field의 name·value + footer.text + author.name 글자 수를 더한 값을 돌려줘요. 이미지 URL이나 링크 주소는 안 세니까 참고하세요.

📌 색상(Colour) 지정하는 3가지 방법

discord.Colourdiscord.Color완전히 같은 클래스예요. 철자는 편한 쪽으로 쓰면 됩니다.

# 1) 이름으로 (가장 간단)
discord.Colour.blurple()   # 디스코드 대표 보라색
discord.Colour.green()
discord.Colour.red()
discord.Colour.gold()

# 2) 직접 값 지정
discord.Colour.from_rgb(88, 101, 242)
discord.Colour.from_str("#5865F2")   # "0x5865F2", "rgb(88, 101, 242)"도 OK
discord.Colour(0x5865F2)             # 16진수 정수 그대로

# 3) 랜덤
discord.Colour.random()
  • blurple : 디스코드 공식 브랜드 컬러예요. 봇 공지에 제일 무난합니다.
  • from_str : 0x5865F2 / #5865F2 / rgb(88, 101, 242) 형식을 전부 받아줘요. 2.0에서 추가됐습니다.
  • random(*, seed=None) : 매번 다른 색. seed를 주면 같은 값엔 같은 색이 나와서 유저별 고정 색상 만들 때 좋아요.

색깔 이름은 이 외에도 teal, magenta, orange, fuchsia, yellow, dark_grey, brand_green, brand_red30가지 넘게 준비돼 있어요.

📌 전체 코드 (복붙 OK)

# discord.py 2.7.1 / Python 3.8+
# 설치: pip install -U discord.py

import datetime

import discord
from discord import app_commands

TOKEN = "여기에_봇_토큰_붙여넣기"

intents = discord.Intents.default()
client = discord.Client(intents=intents)
tree = app_commands.CommandTree(client)


@client.event
async def on_ready():
    await tree.sync()
    print(f"로그인 완료: {client.user}")


@tree.command(name="공지", description="임베드 공지를 보냅니다")
async def notice(interaction: discord.Interaction):
    # 1) 뼈대 만들기
    embed = discord.Embed(
        title="🎉 7월 출석 이벤트 안내",
        description="이번 달 출석 이벤트가 시작됐어요!\n아래 내용을 꼭 확인해주세요.",
        colour=discord.Colour.blurple(),
        url="https://mojangcam.tistory.com/",
        timestamp=datetime.datetime.now(datetime.timezone.utc),
    )

    # 2) 상단 작성자 + 오른쪽 썸네일
    embed.set_author(name="Mojangcam 봇", icon_url=client.user.display_avatar.url)
    embed.set_thumbnail(url=client.user.display_avatar.url)

    # 3) 필드로 항목 정리
    embed.add_field(name="📅 기간", value="7월 1일 ~ 7월 31일", inline=True)
    embed.add_field(name="🎁 보상", value="닉네임 색상 역할", inline=True)
    embed.add_field(name="👥 대상", value="서버 전체 멤버", inline=True)
    embed.add_field(
        name="📌 참여 방법",
        value="매일 `/출석` 명령어를 입력하면 자동 기록돼요.",
        inline=False,
    )

    # 4) 하단 푸터 (글자 수도 같이 표시)
    embed.set_footer(text=f"현재 임베드 길이 {len(embed)}자 / 최대 6000자")

    # 5) 6000자 안전장치
    if len(embed) > 6000:
        await interaction.response.send_message("내용이 너무 길어요! 😥", ephemeral=True)
        return

    await interaction.response.send_message(embed=embed)


client.run(TOKEN)

TOKEN 자리에 본인 봇 토큰만 넣으면 바로 돌아가요. 슬래시 명령어라 서버에 반영되는 데 잠깐 걸릴 수 있습니다.

📌 실행 결과

봇을 켜고 디스코드에서 /공지를 입력하면, 왼쪽에 보라색 띠가 있는 카드가 뜹니다. 상단엔 봇 이름과 아이콘, 그 아래 제목(클릭하면 블로그로 이동), 본문, 그리고 기간·보상·대상 3개가 가로로 나란히 붙고 참여 방법만 한 줄을 통째로 차지해요. 오른쪽 위엔 썸네일, 맨 아래엔 글자 수와 시간이 표시됩니다.

inline=True인 필드가 3개까지 한 줄에 붙는다는 걸 눈으로 확인해보세요. 4번째 필드를 inline=True로 바꾸면 아래 줄로 내려갑니다.

📌 자주 나는 에러

1. TypeError: add_field() takes 1 positional argument but 3 were given

  • 원인 : add_field("제목", "내용")처럼 위치 인자로 넘겼어요. 임베드 메서드는 대부분 키워드 전용입니다.
  • 해결 : add_field(name="제목", value="내용") 형태로 바꿔주세요. set_image, set_footer, set_author도 마찬가지예요.

2. AttributeError: type object 'Embed' has no attribute 'Empty'

  • 원인 : discord.Embed.Empty2.0에서 삭제됐어요. 인터넷에 떠도는 1.x 시절 예제를 그대로 복사하면 이 에러가 납니다.
  • 해결 : 전부 None으로 바꾸면 돼요. if embed.footer.text is not None: 이런 식으로요.

3. discord.errors.HTTPException: 400 Bad Request (error code: 50035)

  • 원인 : 제한값 초과. description 4096자, field.value 1024자, 전체 6000자 중 하나를 넘겼을 확률이 높아요.
  • 해결 : 보내기 전에 print(len(embed))로 찍어보세요. DB에서 가져온 긴 텍스트를 넣을 땐 value=text[:1024]처럼 잘라주는 게 안전합니다.

4. 이미지가 안 뜨고 빈 칸으로 나와요

  • 원인 : set_image(url="C:/images/banner.png")처럼 내 컴퓨터 경로를 넣었어요. 디스코드는 인터넷에서 접근 가능한 http(s) 주소만 읽습니다.
  • 해결 : 인터넷에 올라간 이미지 URL을 쓰거나, 아래 보너스의 attachment:// 방식을 쓰세요.

5. TypeError: unhashable type: 'Embed'

  • 원인 : 임베드를 set에 넣거나 dict의 키로 썼어요. 2.0에서 __eq__가 생기면서 임베드는 해시 불가 객체가 됐습니다.
  • 해결 : list에 담아 관리하세요. 중복 제거가 필요하면 to_dict() 결과를 비교하면 됩니다.

💡 보너스 - 내 컴퓨터 이미지를 임베드에 넣기

로컬 이미지 파일을 쓰고 싶다면 discord.File로 같이 올리고 attachment://파일명으로 참조하면 돼요.

file = discord.File("images/banner.png", filename="banner.png")

embed = discord.Embed(title="오늘의 배너", colour=discord.Colour.gold())
embed.set_image(url="attachment://banner.png")

await interaction.response.send_message(file=file, embed=embed)
  • filename : 여기 적은 이름과 attachment:// 뒤 이름이 정확히 같아야 해요. 대소문자도 구분합니다.
  • 이 방식은 set_image, set_thumbnail, set_footer(icon_url=...), set_author(icon_url=...) 네 군데 모두 사용할 수 있어요.

💡 보너스 - 임베드를 파일로 저장했다가 다시 불러오기

공지 템플릿을 여러 개 관리할 때 유용해요.

import json

# 저장
with open("notice.json", "w", encoding="utf-8") as f:
    json.dump(embed.to_dict(), f, ensure_ascii=False, indent=2)

# 불러오기
with open("notice.json", encoding="utf-8") as f:
    embed = discord.Embed.from_dict(json.load(f))

to_dict()로 dict를 뽑아 JSON에 저장하고, from_dict()로 되살리는 구조예요. 봇을 껐다 켜도 공지 양식이 그대로 남습니다.

📌 마무리

오늘은 디스코드 임베드를 처음부터 끝까지 정리해봤어요! 요약하면 이렇습니다 💬

  • 임베드는 author / title / description / fields / thumbnail / image / footer 자리가 정해져 있어요
  • 메서드 인자는 거의 다 키워드 전용name=, value=, url= 꼭 붙이기
  • 필드 25개 / 전체 6000자가 가장 자주 걸리는 제한값, len(embed)로 미리 체크
  • Embed.Empty는 2.0에서 사라졌어요 → None 사용
  • 로컬 이미지는 discord.File + attachment://파일명

다음 편에서는 디스코드 봇 데이터 저장 - JSON vs SQLite를 다뤄볼게요. 출석 기록이나 유저 포인트처럼 "봇을 껐다 켜도 남아야 하는 데이터"를 어디에 어떻게 저장할지 비교해볼 예정이에요. 기대해주세요! 🙌

궁금한 점은 댓글로 남겨주세요. 임베드 관련해서 막히는 부분 있으면 같이 풀어봐요 😎

📚 디스코드 봇 만들기 시리즈

함께 보면 좋은 글