1. Overview
Mail is a service that helps developers send in-game mails with attachments to players asynchronously through the PGOS web portal or virtual server. Game client can pull mails, mark mails, delete mails and claim the attachment in mails.
Mail can be applied in the following scenarios:
- System Notification: Developers can update notices to players by sending them mails.
- Campaign Events: Developers can configure event triggers for achievements to distribute rewards to players.
- Gifts(not supported yet): A player can purchase in-game items and give them to another player as a gift in the form of sending the player a mail with the items as attachment.
2. Key Concepts
There are three key concepts in mail service:
- Mailbox: Each player has a mailbox once the player registered on PGOS.
- Mail: Mail can be sent to players with real time notification. The mails will be saved in the backend for 3 months. During the validity period, emails can be retrieved and managed by their recipients.
- Attachment: Each mail can be attached with any number of items and currencies. The player can obtain these items and currencies by claiming the attachment.
All mails are kept on backend for by default 90 days. Expired mails will not be viewed or operated. If the time limit needs to be modified, please contact us.
3. Send a Mail
3.1 Send a Mail on the Web Portal
Click the Engagement menu, and you will see the following page.
Field Description:
- Receivers:the receivers of a mail (at most 1000 players can be selected at a time);
- Specified Players: send this mail to limited amount of players
- Global: send this mail to all players
- Category: the category of mail info, eg:
System, Notice, Campaign, Award, Gift, Custom
; - Custom Data: the custom data of mail information. You can define some data and pass it to the SDK;
- Title & Content: the content of a mail. You can define the title and content information in multiple languages;
- Attachments: the attachment(s) in a mail. You can choose in-game item and currency from economy part.
How to Choose Receivers
Send to specified players
Click the + Add
button on the right side of Receivers
Select the mail recipient in the pop-up dialog. You can also add the receiver by searching Player ID.
Send to all players
If global scope is selected, an expiration time must be specified.
When the receivers' scope is set to Global, all players will receive the email. Due to the potentially large number of online players, receiving a Global type email may be delayed by 1-2 minutes. For offline players, the email will be delivered when they log into the game.
Global type mail will only be delivered to players who have logged in or remained online before the deadline. Once the deadline has passed, players who have already received the global mail will keep it, but players who log in after this point will no longer receive the mail.
How to Add Title & Content
Click the + Add Language
button on the bottom of Title & Content, and enter the mail content in the pop-up dialog.
- Language: PGOS provides most of the language types by default, and you can also add language types:
- Title: The subject of the mail with a maximum length of 1024 characters;
- Content: The content of the mail with a maximum length of 4096 characters;
In the Content, you can use the placeholder {{receiver_name}} to represent the receivers' player name. Such as:
Hello {{receiver_name}}, mail contents ......
The first Language you add will be set as the default language, and you can change it.
How to Add Attachments
Click the + Add Attachment
button on the bottom of Attachments
, and choose the mail attachments in the pop-up dialog.
After selecting the In-game Items and Currency associated with the mail, you can set their amount. The attachment's amount can not be less than 1 or bigger then 32-bit unsigned integer (4,294,967,295).
Send a Mail
After confirming that the all informtion is correct, click the Send button at the bottom to send the mail.
Import from Mail Template
You can click Import from Mail Template
to quickly import the Mail Template to fill in the data. How to create a Mail Template, please click here.
3.2 Send a Mail via Virtual Server
The Virtual Server can utilize the following HTTP API endpoints listed in the following table to implement functionalities such as sending and recalling emails.
Interface | Description |
---|---|
SendMail | Send mail to players. Specify receivers, multi-language contents and attachments in requests. |
SendGlobalMail | Send global mail to all players. |
SendMailWithTemplate | Send mail with template. Configure template on web portal first. |
SendGlobalMailWithTemplate | Send global mail with template to all players. |
GetPlayerMails | Get player' mails. This interface supports pagination. |
GetDeletedPlayerMails | Get player' deleted mails (deleted mails will be reserved for 3 months). |
RecoverDeletedMails | Recover deleted mails for specified player. |
RetractGlobalMail | Retract a previously sent global mail. |
4. Mail Template
Switch the top tab to Mail Template, and all the Mail Templates will be displayed.
Create Mail Template
Click the + Add Mail Template
button, as shown below:
Remove Mail Templates
Select the Mail Template you want to delete, click the Delete Mail Template button at the bottom, and click Submit in the pop-up dialog to delete it.
Modify/Clone Mail Template
Select the Mail Template and then click the edit or clone button.
5. Mail Env Variables
You could use mail variables to customize the content of mails that generated when sent. PGOS provides a number of predefined environment variables:
{{receiver_name}}
. Will be replaced with the display name of the mail receiver player.{{goal_name}}
. This is an available that could be used in mails sent by PGOS Goals Service and will be replaced with the name of the player goal that triggered the mail.{{cur_tier_order}}
. This is an available that could be used in the email sent by PGOS Goals Service and will be replaced with the current tier of a hyper goal.
All available variables can be viewed in Engagement>Mails>Mail Env Variables
of portal.
In addition, mail environment variables are allowed to be added and used when send mail.
6. Manage Mails
This chapter mainly introduces the client APIs.
Note:
When sending a mail, the title and content of the mail can be configured in multiple languages, and one of them is the default language. The language type of mails received by players is determined according to the language set by themselves:
- If the multiple languages of the mail contains the player's language, the mail corresponding to the player's language will be returned.
- If there is no language that players use in the multiple languages of the mail, the mail corresponding to the default language will be returned.
Developers can update player's language by calling UPgosPlayerProfileAPI:SetMyLanguage API.
6.1 Data Structure
FClientMailInfo is designed to describe a mail. Key fields in FClientMailInfo are as follows:
- mail_id: The unique identifier of a mail.
- title: The title of the mail.
- category: The category of the mail.
- System: System mail.
- Notice: Game notice mail.
- Campaign: Game campaign mail.
- Award: Used to issue awards to players.
- Gift: A player can purchase in-game items and give to another player as gift in the form of sending the player a mail with the items as an attachment.
- Custom: Custom category, if the above categories are not satisfied, developer can use this to represent a category.
- content: The content of the mail.
- attachment: The attachment of the mail, including In-game Items and Currency.
- custom_data: Custom data for mail.
- is_read: Whether the mail has been read.
- sent_time: The time a mail was sent.
FClientMailAttachmentInfo is designed to describe a mail attachment. Key fields in FClientMailAttachmentInfo are as follows:
- items: An array of In-game Items waiting to be claimed.
- currencies: An array of Currencies waiting to be claimed.
- is_gift_from_player: Whether the attachment was gifted by another player.
- giver: If
is_gift_from_player
is true, 'giver' represents the player who give the gift. - is_claimed: Whether the attachment has been claimed.
6.2 Get Mail List
Players can paginate to get their mail list by calling UPgosMailAPI::GetMailList
API. Players can specify the category of the mail when get it, and EClientMailCategory::All
represents all categorys of mail.
Interface prototype:
/**
* Get mail list by category, category 'All' represents all categories.
*
* @param Params Request parameters for get mail list.
*/
void GetMailList(
const FClientGetMailListParams& Params,
TFunction<void(const FPgosResult& Ret, const FClientGetMailListResult* Data)> Callback) const;
/** Request parameters for get mail list. */
struct FClientGetMailListParams {
/** Query the specified category. */
MailCategory category;
/** The starting position of the list. */
uint32_t offset = 0;
/** The query count. */
uint32_t count = 0;
};
Example Code:
#include "PgosSDKCpp.h"
void SomeUObjectClass::SomeFunction()
{
auto Mail = IPgosSDKCpp::Get().GetClientMailAPI();
if (Mail)
{
FClientGetMailListParams Params;
// Fill get mail list params
Mail->GetMailList(Params, [](const FPgosResult& Ret, const FClientGetMailListResult* Data) {
if (Ret.err_code == (int32)Pgos::PgosErrCode::kSuccess)
{
UE_LOG(LogTemp, Log, TEXT("GetMailList Successfully"));
}
else
{
UE_LOG(LogTemp, Log, TEXT("GetMailList Failed: err_code=%d, err_msg=%s"), Ret.err_code, *Ret.msg);
}
});
}
}
Key Error Codes
6.3 Mark Mails as Read
Players can mark mails as read by calling UPgosMailAPI::MarkMailAsReadById
/UPgosMailAPI::MarkMailAsReadByCategory
API. IT respectively means to mark the mail status by id and category.
In UPgosMailAPI::MarkMailAsReadByCategory
API, EClientMailCategory::All
represents all categorys.
Interface prototype:
/**
* Mark mail as read by id.
*
* @param MailIds Mail IDs.
*/
void MarkMailAsReadById(
const TArray<FString>& MailIds,
TFunction<void(const FPgosResult& Ret)> Callback) const;
/**
* Mark mail as read by category.
*
* @param Category Mail category, category 'All' represents all categories.
*/
void MarkMailAsReadByCategory(
EClientMailCategory Category,
TFunction<void(const FPgosResult& Ret)> Callback) const;
Example Code:
#include "PgosSDKCpp.h"
void SomeUObjectClass::SomeFunction()
{
auto Mail = IPgosSDKCpp::Get().GetClientMailAPI();
if (Mail)
{
TArray<FString> MailIds;
Mail->MarkMailAsReadById(MailIds, [](const FPgosResult& Ret) {
if (Ret.err_code == (int32)Pgos::PgosErrCode::kSuccess)
{
UE_LOG(LogTemp, Log, TEXT("MarkMailAsReadById Successfully"));
}
else
{
UE_LOG(LogTemp, Log, TEXT("MarkMailAsReadById Failed: err_code=%d, err_msg=%s"), Ret.err_code, *Ret.msg);
}
});
}
}
void SomeUObjectClass::SomeFunction1()
{
auto Mail = IPgosSDKCpp::Get().GetClientMailAPI();
if (Mail)
{
EClientMailCategory Category;
// specify mail category
Mail->MarkMailAsReadByCategory(Category, [](const FPgosResult& Ret) {
if (Ret.err_code == (int32)Pgos::PgosErrCode::kSuccess)
{
UE_LOG(LogTemp, Log, TEXT("MarkMailAsReadByCategory Successfully"));
}
else
{
UE_LOG(LogTemp, Log, TEXT("MarkMailAsReadByCategory Failed: err_code=%d, err_msg=%s"), Ret.err_code, *Ret.msg);
}
});
}
}
6.4 Claim Attachments in a Mail
Players can claim mail attachments by calling UPgosMailAPI::ClaimMailAttachmentById
/UPgosMailAPI::ClaimMailAttachmentByCategory
API. After the attachments is successfully claimed, players can find the item instances in player inventory and currencies in balances.
In UPgosMailAPI::ClaimMailAttachmentByCategory
API, EClientMailCategory::All
represents all categorys.
An unread mail will be automatically marked as read when its attachment is successfully claimed.
The returned results are saved in the FClientClaimMailAttachmentResult
structure:
struct FClientClaimMailAttachmentResult
{
/** The item instances obtained after claim attachments. */
FItemInstPack item_insts;
/** The currencies obtained after claim attachments. */
TArray<FCurrency> currencies;
/** Unique items that already in inventory cause failed to be granted. */
TArray<FUnclaimedItem> conflict_unique_items;
/** Mails that failed to claim attachments, key: mail ID, value: failed reason. */
TMap<FString, FString> fails;
};
Interface prototype:
/**
* Claim mail attachments by mail ID.
*
* @param MailIds Mail IDs.
*/
void ClaimMailAttachmentById(
const TArray<FString>& MailIds,
TFunction<void(const FPgosResult& Ret, const FClientClaimMailAttachmentResult* Data)> Callback) const;
/**
* Claim mail attachments by category.
*
* @param Category Mail category, category 'All' represents all categories.
*/
void ClaimMailAttachmentByCategory(
EClientMailCategory Category,
TFunction<void(const FPgosResult& Ret, const FClientClaimMailAttachmentResult* Data)> Callback) const;
Example Code:
#include "PgosSDKCpp.h"
void SomeUObjectClass::SomeFunction()
{
auto Mail = IPgosSDKCpp::Get().GetClientMailAPI();
if (Mail)
{
TArray<FString> MailIds;
Mail->ClaimMailAttachmentById(MailIds, [](const FPgosResult& Ret, const FClientClaimMailAttachmentResult* Data) {
if (Ret.err_code == (int32)Pgos::PgosErrCode::kSuccess)
{
UE_LOG(LogTemp, Log, TEXT("ClaimMailAttachmentById Successfully"));
}
else
{
UE_LOG(LogTemp, Log, TEXT("ClaimMailAttachmentById Failed: err_code=%d, err_msg=%s"), Ret.err_code, *Ret.msg);
}
});
}
}
void SomeUObjectClass::SomeFunction1()
{
auto Mail = IPgosSDKCpp::Get().GetClientMailAPI();
if (Mail)
{
EClientMailCategory Category;
// specify mail category
Mail->ClaimMailAttachmentByCategory(Category, [](const FPgosResult& Ret, const FClientClaimMailAttachmentResult* Data) {
if (Ret.err_code == (int32)Pgos::PgosErrCode::kSuccess)
{
UE_LOG(LogTemp, Log, TEXT("ClaimMailAttachmentByCategory Successfully"));
}
else
{
UE_LOG(LogTemp, Log, TEXT("ClaimMailAttachmentByCategory Failed: err_code=%d, err_msg=%s"), Ret.err_code, *Ret.msg);
}
});
}
}
Key Error Codes
6.5 Delete Mails
Players can delete mails by calling UPgosMailAPI::DeleteMailById
/UPgosMailAPI::DeleteReadMailByCategory
API. IT respectively means to delete mail by id and by category. It should be noted that UPgosMailAPI::DeleteReadMailByCategory
is to delete the read mails by category, and UPgosMailAPI::DeleteMailById
does not distinguish between read and unread.
In UPgosMailAPI::ClaimMailAttachmentByCategory
API, EClientMailCategory::All
represents all categorys.
Interface prototype:
/**
* Delete mail by mail ID.
*
* @param MailIds Mail IDs.
*/
void DeleteMailById(
const TArray<FString>& MailIds,
TFunction<void(const FPgosResult& Ret)> Callback) const;
/**
* Delete read mails by category.
*
* @param Category Mail category, category 'All' represents all categories.
*/
void DeleteReadMailByCategory(
EClientMailCategory Category,
TFunction<void(const FPgosResult& Ret)> Callback) const;
Example Code:
#include "PgosSDKCpp.h"
void SomeUObjectClass::SomeFunction()
{
auto Mail = IPgosSDKCpp::Get().GetClientMailAPI();
if (Mail)
{
TArray<FString> MailIds;
Mail->DeleteMailById(MailIds, [](const FPgosResult& Ret) {
if (Ret.err_code == (int32)Pgos::PgosErrCode::kSuccess)
{
UE_LOG(LogTemp, Log, TEXT("DeleteMailById Successfully"));
}
else
{
UE_LOG(LogTemp, Log, TEXT("DeleteMailById Failed: err_code=%d, err_msg=%s"), Ret.err_code, *Ret.msg);
}
});
}
}
void SomeUObjectClass::SomeFunction()
{
auto Mail = IPgosSDKCpp::Get().GetClientMailAPI();
if (Mail)
{
EClientMailCategory Category;
Mail->DeleteReadMailByCategory(Category, [](const FPgosResult& Ret) {
if (Ret.err_code == (int32)Pgos::PgosErrCode::kSuccess)
{
UE_LOG(LogTemp, Log, TEXT("DeleteReadMailByCategory Successfully"));
}
else
{
UE_LOG(LogTemp, Log, TEXT("DeleteReadMailByCategory Failed: err_code=%d, err_msg=%s"), Ret.err_code, *Ret.msg);
}
});
}
}
6.6 Get the Count of Unread Mails
Players can get unread count per category, as well as total unread count by calling UPgosMailAPI::GetMailBadgeNum
API.
Interface prototype:
/**
* Get the count of unread mails.
*/
void GetMailBadgeNum(TFunction<void(const FPgosResult& Ret, const FClientGetMailBadgeNumResult* Data)> Callback) const;
Example Code:
#include "PgosSDKCpp.h"
void SomeUObjectClass::SomeFunction()
{
auto Mail = IPgosSDKCpp::Get().GetClientMailAPI();
if (Mail)
{
Mail->GetMailBadgeNum([](const FPgosResult& Ret, const FClientGetMailBadgeNumResult* Data) {
if (Ret.err_code == (int32)Pgos::PgosErrCode::kSuccess)
{
UE_LOG(LogTemp, Log, TEXT("GetMailBadgeNum Successfully"));
}
else
{
UE_LOG(LogTemp, Log, TEXT("GetMailBadgeNum Failed: err_code=%d, err_msg=%s"), Ret.err_code, *Ret.msg);
}
});
}
}
6.7 Monitor Mail Events
Some events will be triggered when using the mail:
- OnBadgeNumOfMail: Immediately triggered after login, and subsequently, it will also be triggered whenever there is a change in the unread count. The event results are saved in
FClientBadgeNumOfMailEvt
. - OnReceiveNewMail: This event is triggered in real-time when new mails arrive, it should be noted that mails received while offline will not trigger this event. The event results are saved in
FClientReceiveNewMailEvt
.
struct FClientBadgeNumOfMailEvt
{
/** Total unread count. */
int32 total_badge_num = 0;
};
struct FClientReceiveNewMailEvt
{
/** New mail. */
FClientMailInfo mail;
};
7. Key Errors Handling
Error Code | Relevant API | Handling Suggestion |
---|---|---|
kBackendReceiverIDIllegal kBackendReceiverEmpty | SendMail | Sender must specify at least one valid PlayerID to send mail successfully. Mail will throw an error if one of the PlayerIDs are invalid. |
kBackendDefaultLanguageNotExist | SendMail | Mail will respond mails to player in his local language defined in player info, when local language missing, mail will use the default language instead. So the sender must ensure the mail text map contains the default_language key. |
kBackendIllegalCategoryEnum | SendMail | Sender must specify a valid category enum when sending a mail. And MAIL_CATEGORY_ALL cannot be used since it has special meaning in batch processing interfaces. |
kBackendMailTitleContainProfanityWords kBackendMailContentContainProfanityWords | SendMail | Sender must ensure that the title and content of mail do not contain profane words. |
kBackendGetMailCountBeyondLimit | GetMailList | Get mail count cannot be zero or exceed 100 |
kBackendGrantItemNumExceed | ClaimMailAttachmentById ClaimMailAttachmentByCategory | Grant items num exceeds limit |
kBackendCheckIdempotentKeyFailed | SendMail | There is an issue with idempotent key duplication. |