RedM documentation

Murphy's Telegram & Mail

Advanced

External API


Murphy's Telegram & Mail exposes exports and events so other resources can send mail programmatically.

External HUD Integration (Statebag)

murphy_post can sync the player's pending inbox count to a player statebag so any external HUD or resource can read it directly - no event listeners or extra glue required.

Configuration

lua
-- config/config.lua
Config.InboxStateBag = {
enabled = true, -- set to false to disable the sync
key = 'telegramUnreadMessages', -- statebag key (BLN HUD default)
}

When enabled, the client updates LocalPlayer.state[] every time the count changes:

  • on character selection (initial fetch)
  • when a new letter or telegram becomes available for pickup
  • when the player picks one up at the post office The value is the number of letters/telegrams currently awaiting pickup in the player's personal inbox (delayed mail is excluded until it becomes available). BLN HUD reads LocalPlayer.state.telegramUnreadMessages by default, so the integration is plug-and-play - just leave the default key:
lua
-- BLN HUD config
Config.Telegram = {
animateMessagesCount = true,
getUnreadMessagesCount = function()
return LocalPlayer.state.telegramUnreadMessages or 0
end,
}

Custom HUDs / resources

Any client-side script can read the value:

lua
local count = LocalPlayer.state.telegramUnreadMessages or 0

Or watch for changes:

lua
AddStateBagChangeHandler('telegramUnreadMessages', ('player:%s'):format(GetPlayerServerId(PlayerId())), function(_, _, value)
print('You now have ' .. tostring(value) .. ' letters waiting at the post office.')
end)

Disabling

If you don't want murphy_post to touch any statebag, set Config.InboxStateBag.enabled = false. The in-game HUD icon (Config.InboxIcon) keeps working independently.

Methods

lua
local result = exports.murphy_post:SendTelegram(senderData, recipientData, telegramData, options)
local result = exports.murphy_post:SendLetter(senderData, recipientData, letterData, options)

Events

lua
TriggerEvent('murphy_post:sendTelegramExternal', senderData, recipientData, telegramData, options, function(result)
-- handle result
end)
TriggerEvent('murphy_post:sendLetterExternal', senderData, recipientData, letterData, options, function(result)
-- handle result
end)

Parameters

senderData (table, optional)

Field Type Required Default Description
identifier string No "SYSTEM" Sender's character identifier
firstname string No "System" Sender's first name
lastname string No "Admin" Sender's last name
officeId string No nil Post office origin ID

recipientData (table)

Option A - Send to a person:

lua
{ firstName = "John", lastName = "Marston" }

Option B - Send to a job mailbox:

lua
{ mailboxId = "sheriff_rhodes" }
Field Type Required Description
firstName string Yes (if no mailboxId) Recipient's first name
lastName string Yes (if no mailboxId) Recipient's last name
mailboxId string Yes (if no name) Target mailbox ID

telegramData (table)

Field Type Required Description
object string Yes Subject line
body string Yes Message body
signature string No Sender signature (defaults to sender name)
templateId string No Telegram template ID
fontId string No Font override

letterData (table)

Field Type Required Description
object string Yes Subject line
body string Yes Message body
signature string No Sender signature (defaults to sender name)
packageType string No Item name to attach as package
amount number No Package item quantity
packageMeta table No Package item metadata
templateId string No Letter template ID
fontId string No Font override

options (table, optional)

Field Type Default Description
delay number Config value Seconds before document becomes available

Return value

lua
{
ok = true, -- boolean: success or failure
id = 123, -- number: created document ID (if ok = true)
error = "..." -- string: error code (if ok = false)
}

Error codes

Code Description
recipient_not_found First/last name doesn't match any character
missing_mailbox Mailbox routing requested but no mailboxId provided
db_insert_failed Database insert error

Important notes

No automatic charge

The exports do not charge the sender. If you want to bill the player, handle payment before calling the export:

lua
if ChargeMoney(source, 10) then
local result = exports.murphy_post:SendTelegram(senderData, recipientData, telegramData)
if not result.ok then
RefundMoney(source, 10) -- refund on failure
end
end

Package items are NOT removed from inventory

When sending a letter with packageType, the item is not automatically removed from the sender's inventory. You must remove it yourself before calling the export:

lua
if RemoveItem(source, 'bread', 5) then
exports.murphy_post:SendLetter(senderData, recipientData, {
object = 'Supplies',
body = 'Here is some bread for your journey.',
packageType = 'bread',
amount = 5
})
end

Notifications

If the recipient is online and notifications are enabled (Config.LetterNotification / Config.TelegramNotification), they will receive an in-game notification.

Offline recipients

Mail sent to offline players is stored in the database. They will find it in their inbox next time they visit a post office.

Examples

Simple telegram to a player

lua
local result = exports.murphy_post:SendTelegram(
{
identifier = 'bank_system',
firstname = 'Bank',
lastname = 'of Lemoyne'
},
{
firstName = 'John',
lastName = 'Marston'
},
{
object = 'Weekly Statement',
body = string.format('Dear client,\n\nYour weekly interest has been applied.\nNew balance: $%.2f', newBalance),
signature = 'The Management'
},
{ delay = 0 }
)

Letter with item package

lua
local result = exports.murphy_post:SendLetter(
{
identifier = 'quest_system',
firstname = 'Quest',
lastname = 'Master'
},
{
firstName = 'Arthur',
lastName = 'Morgan'
},
{
object = 'Quest Reward',
body = 'Congratulations on completing the quest! Your reward is attached.',
signature = 'The Quest Master',
packageType = 'gold_bar',
amount = 2
},
{ delay = 300 } -- available in 5 minutes
)

Telegram to a job mailbox

lua
local result = exports.murphy_post:SendTelegram(
{}, -- defaults to System Admin
{
mailboxId = 'sheriff_rhodes'
},
{
object = 'Crime Report',
body = 'A robbery was reported near the Valentine train station.',
signature = 'Anonymous Citizen'
}
)

Newsletter to all online players

lua
local players = GetPlayers()
for _, playerId in ipairs(players) do
local pid = tonumber(playerId)
local firstname = GetCharFirstname(pid)
local lastname = GetCharLastname(pid)
if firstname and lastname then
exports.murphy_post:SendTelegram(
{ identifier = 'admin', firstname = 'Server', lastname = 'Admin' },
{ firstName = firstname, lastName = lastname },
{ object = 'Server Announcement', body = 'Important news...', signature = 'Staff Team' },
{ delay = 0 }
)
end
end

Scheduled reminder

lua
exports.murphy_post:SendTelegram(
{ identifier = 'reminder', firstname = 'Reminder', lastname = 'System' },
{ firstName = 'John', lastName = 'Marston' },
{ object = 'Appointment Reminder', body = 'Your appointment is in 1 hour.', signature = 'Auto-Reminder' },
{ delay = 3600 } -- delivered in 1 hour
)

Last updated: September 9, 2026