우편 발송
SendMailAsync()를 호출해 운영 우편이나 보상 우편을 발송합니다. 발송 전에 수신 대상, 본문 유형, 첨부 아이템, 만료 시각을 준비하고 응답에서 받은 MailId를 저장해 필요할 때 조회와 회수에 사용합니다.
1. 발송 요청값 준비
우편 발송 호출 파라미터는 수신 대상, 우편 내용, 만료 정책으로 구성합니다. 발송 전에 세 가지를 먼저 결정합니다.
1.1. 수신 대상 설정
RecipientScope로 우편을 모든 사용자에게 보낼지, 지정한 사용자에게만 보낼지 결정합니다. 지정한 사용자에게 보내는 우편이면 RecipientPlayerIds에 수신자 PlayerId 목록을 넣습니다.
Broadcast: 모든 사용자에게 발송Direct:RecipientPlayerIds에 지정한 사용자에게 발송RecipientPlayerIds:Direct일 때 반드시 지정하는 수신자PlayerId목록, 최대 100개
PlayerId는 사용자 로그인 계정 생성 후 발급받는 사용자 식별자입니다.
우편함 메서드는 로그인한 사용자 세션으로 호출하므로 Broadcast는 지정할 수 없습니다. Broadcast로 요청하면 발송 결과가 BroadcastMailNotAllowedForUser로 돌아오므로, Direct로 수신자를 지정해 발송하세요.
1.2. 우편 내용과 첨부 아이템 구성
MailContentType은 우편이 본문만 있는지, 첨부 아이템이 있는지 구분하는 값입니다. 첨부 아이템이 있는 우편이면 Attachments를 함께 채우고 각 항목에 첨부 아이템 타입, 참조 ID, 수량을 넣습니다.
Text: 본문만 있는 우편Attachment: 본문과 첨부 아이템이 함께 있는 우편Attachments:MailContentType이Attachment일 때만 전달하는 첨부 아이템 목록, 최대 10개
첨부 아이템이 유효한지 검증하는 작업과 앱 내에서 첨부 아이템을 지급, 수령, 소진하는 작업은 앱에서 직접 구현해야 합니다.
제목 Title, 본문 Body와 함께 SenderDisplayName도 반드시 전달합니다. SenderDisplayName은 사용자가 우편 화면에서 보는 발신자 이름으로, 발송 시점의 값을 그대로 저장합니다. 따라서 나중에 발신자 이름을 바꿔도 이미 발송한 우편에는 반영되지 않습니다.
1.3. 만료 시각과 우편 운영 정책 정리
ExpiresAt은 UTC 기준 우편 만료 시각입니다. 현재 UTC 시각으로부터 30일을 넘는 시각은 설정할 수 없습니다. Language, MailCategory, MailExtension은 앱 정책에 맞게 정리해 함께 전달합니다.
2. 우편 발송
SendMailAsync
SendMailAsync()를 호출해 우편 발송을 요청합니다. 요청을 접수하면 202 Accepted에 해당하는 비동기 접수 응답을 반환합니다. 응답 데이터의 MailId는 필요할 때 발신 우편 정보 조회와 우편 회수에 사용합니다.
Note
우편이 정상 생성되면 발송 요청이 접수된 것으로 간주합니다. 수신자 PlayerId 유효성 검증이나 첨부 아이템 중복 지급 방지 로직이 필요하면 우편 발송 전에 앱 서버에서 먼저 검증하는 것을 권장합니다.
중복 발송 방지(멱등성)
Hive Axyl SDK는 우편 발송 시 요청을 구분하는 멱등 키(Idempotency-Key)를 자동으로 생성해 전송합니다. 자동 생성된 키는 SendMailAsync() 호출 1회당 하나씩 새로 만들어지며, 네트워크 오류로 SDK가 내부적으로 전송을 재시도할 때만 같은 키를 유지합니다.
우편함 서버는 멱등 키와 요청 내용이 모두 동일한 요청이 60분 이내에 다시 들어오면 중복 요청으로 판단하고, 최초 발송한 우편만 수신자에게 전달합니다. 멱등 키의 유효 기간은 60분입니다.
따라서 앱이 SendMailAsync()를 두 번 호출하면 요청 내용이 같더라도 키가 서로 달라 각각 별개의 우편으로 발송됩니다. 재시도 로직으로 같은 우편이 두 번 발송되는 것을 막으려면 호출 단위 설정 객체인 ApiCallContext의 IdempotencyKey에 앱이 직접 생성한 동일한 키를 지정해 호출하세요.
호출 파라미터
| 필드명 | 타입 | 필수 여부 | 설명 |
|---|---|---|---|
request | SendMailRequest | Required | 우편 발송 요청 |
context | ApiCallContext? | Optional | 호출 단위 설정 객체입니다. 생략하면 기본값이 사용됩니다. |
SendMailRequest
| 필드명 | 타입 | 필수 여부 | 설명 |
|---|---|---|---|
SenderDisplayName | string | Required | 우편 화면에 표시할 발신자 이름, 최대 100자. 발송 시점의 값을 저장하므로 이후 이름을 바꿔도 이미 발송한 우편에는 반영되지 않음 |
RecipientScope | SendMailRequestRecipientScope | Required | 수신 대상 범위. Broadcast 또는 Direct. 기본값이 없으므로 반드시 지정 |
RecipientPlayerIds | IReadOnlyList<long>? | Optional | 수신자 PlayerId 목록, 최대 100개. Direct일 때는 반드시 지정 |
MailContentType | SendMailRequestMailContentType | Required | 본문 유형. Text 또는 Attachment. 기본값이 없으므로 반드시 지정 |
Title | string | Required | 우편 제목, 최대 300자 |
Body | string | Required | 우편 본문, 최대 1000자 |
Language | LanguageCode | Required | 우편 언어. Ko, En 등. 기본값이 없으므로 반드시 지정 |
ExpiresAt | DateTimeOffset | Required | UTC 기준 우편 만료 시각. 현재 UTC 시각으로부터 최대 30일 이내의 시각만 설정 가능 |
MailCategory | string | Optional | 우편함 카테고리. 기본값 "DEFAULT", 최대 64자 |
Attachments | IReadOnlyList<AttachmentItem>? | Optional | 첨부 아이템 목록. Attachment일 때만 사용. 최대 10개 |
MailExtension | string? | Optional | 앱에서 정의한 정책 문자열. 우편 노출 조건이나 수령 조건 등 앱 정책 정보를 저장할 때 사용. 서버는 이 값을 해석하지 않고 그대로 저장. 최대 4096자 |
AttachmentItem
| 필드명 | 타입 | 필수 여부 | 설명 |
|---|---|---|---|
AttachmentType | string | Optional | 첨부 아이템 타입. 기본값 "DEFAULT", 최대 30자 |
ReferenceId | string | Required | 첨부 아이템 참조 ID, 최대 100자 |
Quantity | int | Required | 지급 수량 |
호출 예시
MailboxSendMailResult의 성공 결과와 이 메서드의 도메인별 결과(Outcome)는 아래 예시와 응답 상태에서 확인합니다. 요청을 수행할 수 없을 때 반환하는 공통 실패(Failure)의 결과 모델과 처리 원칙은 공통 오류 처리를 참조하세요.
using Hive.Axyl.Mailbox;
using Hive.Axyl.Core;
IMailboxService mailbox = HiveCore.Resolve<IMailboxService>();
var request = new SendMailRequest {
SenderDisplayName = "운영팀",
RecipientScope = SendMailRequestRecipientScope.Direct,
RecipientPlayerIds = new long[] { 12345, 67890 },
MailContentType = SendMailRequestMailContentType.Attachment,
Title = "보상 우편",
Body = "랭킹 보상을 보내드립니다.",
Language = LanguageCode.Ko,
MailExtension = "claimCondition=season_rank",
ExpiresAt = System.DateTimeOffset.UtcNow.AddDays(7),
Attachments = new[] {
new AttachmentItem {
AttachmentType = "ITEM",
ReferenceId = "potion_100",
Quantity = 5,
},
},
};
MailboxSendMailResult result = await mailbox.SendMailAsync(request);
switch (result)
{
case MailboxSendMailResult.Success success:
string? mailId = success.Data.MailId;
break;
case MailboxSendMailResult.BroadcastMailNotAllowedForUser:
// 우편 발송 정책상 허용되지 않는 요청 (broadcast_mail_not_allowed_for_user)
Debug.LogWarning("모든 사용자에게 보내는 우편은 로그인 세션으로 발송할 수 없습니다.");
break;
case MailboxSendMailResult.Failure failure:
HiveError err = failure.Problem;
Debug.LogError($"[{err.Code}] {err.Message} (trace: {err.TraceId})");
break;
default:
Debug.LogWarning($"처리되지 않은 결과: {result.GetType().Name}");
break;
}
응답 데이터
성공 시 MailboxSendMailResult.Success의 Data(AcceptedResponseData)에 결과가 담깁니다. Data.MailId는 필요할 때 조회와 회수에 사용하는 핵심 식별자입니다.
두 필드 모두 null을 담을 수 있는 형식으로 선언되어 있으므로, 값을 화면에 표시하거나 다음 호출에 넘기기 전에 null인지 먼저 확인하세요.
| 필드명 | 타입 | 필수 여부 | 설명 |
|---|---|---|---|
Data.MailId | string? | Optional | 발신 우편 식별자 |
Data.AcceptedAt | DateTimeOffset? | Optional | 발송 요청이 접수된 시각 |
Warning
Data.MailId는 발신 우편 정보 조회와 우편 회수에 사용하므로 반드시 저장해야 합니다. 안전한 저장소에 보관하고 외부에 노출되지 않도록 주의하세요.
응답 예시
응답 상태
반환 객체 MailboxSendMailResult는 아래 케이스 중 하나로 분기됩니다. switch 구문으로 처리를 권장합니다.
| 응답 케이스 | 설명 | 앱 클라이언트 대응 |
|---|---|---|
Success | 발송 요청이 접수됨. Data.MailId와 Data.AcceptedAt이 반환됩니다. 중복 요청으로 판단된 경우에도 Success를 반환합니다. | MailId를 저장한 뒤 필요할 때 상태 조회나 회수에 사용. 발송 건수를 집계한다면 MailId 기준으로 중복을 걸러 냅니다. |
BroadcastMailNotAllowedForUser | 로그인 세션으로는 모든 사용자에게 보내는 우편을 발송할 수 없습니다. 서버 오류 코드는 broadcast_mail_not_allowed_for_user입니다. | RecipientScope를 Direct로 바꾸고 RecipientPlayerIds에 수신자를 지정해 다시 발송 |
Failure | 공통 Failure입니다. 공통 오류 처리를 참조하세요. | 공통 오류 처리 기준에 따라 처리 |
UnknownOutcome | 이 SDK 버전이 알지 못하는 신규 결과입니다. | 실패로 처리하고 결과 코드를 기록 |
다음 단계
발송한 우편의 상태를 다시 확인하거나 회수가 필요하면 발신 우편 정보 조회와 우편 회수를 참조하세요.
발송 직후 상태를 확인하려면 저장한 MailId로 단일 상세 조회를 사용하고, 여러 발신 이력을 함께 볼 때만 목록 조회를 추가로 사용합니다.