文档菜单
Ruby / SDK REFERENCE
Ruby on Rails SDK 指南
用于发送 Kakao 通知消息、好友消息、品牌消息与 SMS 的官方 Rails 集成包 —— 由 Railtie 配置,支持环境变量回退。
이 문서의 목차
- 패키지
- sendgo-rails
- 언어
- Ruby
- 레지스트리
- RubyGems
bundle add sendgo-rails用于发送 Kakao 通知消息、品牌消息与短信的官方 Rails 集成包
sendgo-rails 通过 Railtie 封装 sendgo 核心 gem:新增 config.sendgo 命名空间、支持环境变量回退,并以 Sendgo::Rails.client 暴露一个记忆化的客户端。
安装
# Gemfile
gem "sendgo-rails"
bundle install
bin/rails g sendgo:install
生成器会写出 config/initializers/sendgo.rb。核心 sendgo gem 会作为依赖一并安装。
要求 Ruby 3.1+ 与 Rails 6.1 或更高版本(railties >= 6.1)。
配置
# config/initializers/sendgo.rb
Rails.application.config.sendgo.tap do |config|
config.access_key = ENV["SENDGO_ACCESS_KEY"]
config.secret_key = ENV["SENDGO_SECRET_KEY"]
config.kakao_sender_key = ENV["SENDGO_KAKAO_SENDER_KEY"]
config.sms_sender_key = ENV["SENDGO_SMS_SENDER_KEY"]
config.api_version = ENV.fetch("SENDGO_API_VERSION", "v2")
config.url = ENV.fetch("SENDGO_URL", "https://sendgo.io")
end
每一项配置都按两步解析:先看 config.sendgo.<key>,再回退到同名环境变量。因此在 initializer 里把某个值留为 nil 与完全不设置是等价的 —— 环境变量会生效。这也意味着你可以完全不要 initializer,只用环境变量来配置本 gem。
如果更倾向使用 Rails credentials:
config.access_key = Rails.application.credentials.dig(:sendgo, :access_key)
api_version 在 Rails 集成中默认为 v2(纯 Ruby 核心默认为 v1)。
快速上手
Sendgo::Rails.client.alimtalk.send(
template_code: "ORDER_CONFIRM_001",
contacts: [{ contact: "01012345678", var1: "ORD-001" }]
)
Sendgo::Rails.client 是记忆化且惰性的 —— 直到首次调用才会构建,因此仅仅 require 本 gem 不会在启动期读取配置。核心 gem 的各渠道都可用:
| 方法 | 渠道 |
|---|---|
client.alimtalk |
Kakao 通知消息 |
client.friendtalk |
Kakao 好友消息 |
client.brand_message |
Kakao 品牌消息(仅 v2) |
client.sms |
SMS / LMS / MMS |
由于客户端被记忆化,运行期修改 config.sendgo 在调用 Sendgo::Rails.reset! 之前不会生效。
封装成自己的类
在控制器里到处调用 Sendgo::Rails.client 会把模板代码散落各处。一个薄薄的对象能把它们集中起来,也给测试提供了可替换的接缝:
# app/services/order_notifier.rb
class OrderNotifier
def initialize(client: Sendgo::Rails.client)
@client = client
end
def confirmed(order)
@client.alimtalk.send(
template_code: "ORDER_CONFIRM_001",
contacts: [{ contact: order.phone, var1: order.number }]
)
end
end
品牌消息
好友消息已于 2025-12-31 停止服务。 自 2026-01-01 起,Kakao 会将好友消息请求 自动改以品牌消息(自由形式)发出。
friendtalk仍可调用,且自由文本类型FT/FI/FW发往单个接收者的路径目前仍只有这一条 —— 基于模板的富文本类型 (FL/FC/FM/FP/FA)、非好友定向(N/I)与群发(F)请使用品牌消息。 品牌消息是好友消息的后继渠道:可触达非频道好友的接收者(targeting: "N"),也可向已同意接收的全部频道好友群发(targeting: "F")。消息类型与好友消息一一对应(FT→BT、FI→BI、FW→BW、FL→BL、FC→BC、FM→BM、FP→BP、FA→BA)—— 传入好友消息的代码,服务端会自动转换。
仅 v2 支持,也是 Rails 集成的默认版本。
client = Sendgo::Rails.client
# 单条发送 —— targeting 为 M/N/I 时必须提供 contacts
client.brand_message.send(
targeting: "M",
message_type: "FL",
friend_template_uuid: "9cd5460b-6458-4edc-9b11-c26d3013c340",
contacts: [{ contact: "01012345678", var1: "29,000元" }]
)
# 群发 —— 已同意接收的全部频道好友(不传接收者列表)
result = client.brand_message.broadcast(
message_type: "FW",
friend_template_uuid: "9cd5460b-6458-4edc-9b11-c26d3013c340"
)
# 群发在上游为异步处理,需轮询查看进度
client.brand_message.campaign(result.dig("data", "campaignId"))
client.brand_message.campaigns(from: "2026-08-01", count: 10)
friend_template_uuid 是必填的关键字参数;message_type 默认为 "FT",targeting 默认为 "M"。broadcast 等同于把 targeting 固定为 "F" 的 send,两者接受相同的参数。
群发可能触达整个好友列表,请放在受权限保护的管理操作或 rake 任务里,不要暴露为公开路由。
targeting 的取值含义:
| 值 | 含义 |
|---|---|
M |
频道好友中的指定接收者 |
N |
非频道好友的接收者 |
I |
按标识符指定的接收者 |
F |
已同意接收的全部频道好友(群发) |
从模型回调中发送
请在事务提交之后发送 —— 在事务内触发的回调,即使记录随后因校验失败被回滚,消息也已经发出去了:
class Order < ApplicationRecord
after_commit :notify_customer, on: :create
private
def notify_customer
OrderConfirmJob.perform_later(id)
end
end
ActiveJob
发送是一次网络调用,请不要放在请求周期里:
# app/jobs/order_confirm_job.rb
class OrderConfirmJob < ApplicationJob
queue_as :notifications
# 5xx 为临时故障;4xx 重试也不会成功。
# `:polynomially_longer` 需要 Rails 7.1+;6.1–7.0 请用 `:exponentially_longer`。
retry_on Sendgo::SendgoError, wait: :polynomially_longer, attempts: 3 do |job, error|
raise error if error.status_code >= 500
Rails.logger.error("Sendgo #{error.status_code} [#{error.error_code}]: #{error.message}")
end
def perform(order_id)
order = Order.find(order_id)
Sendgo::Rails.client.alimtalk.send(
template_code: "ORDER_CONFIRM_001",
contacts: [{ contact: order.phone, var1: order.number }]
)
end
end
带块的 retry_on 会在重试次数耗尽之后执行该块。若想遇到 4xx 立即停止,请在 perform 内 rescue 并改用 discard_on:
discard_on Sendgo::SendgoError do |_job, error|
Rails.logger.error("已丢弃:Sendgo #{error.error_code}")
end
Rake 任务
# lib/tasks/promo.rake
namespace :promo do
desc "向已同意接收的全部频道好友群发当前促销"
task broadcast: :environment do
result = Sendgo::Rails.client.brand_message.broadcast(
message_type: "FW",
friend_template_uuid: "9cd5460b-6458-4edc-9b11-c26d3013c340"
)
puts "已接受:#{result.dig('data', 'campaignId')}"
end
end
测试
reset! 会丢弃已记忆化的客户端,这正是让打桩生效的关键:
# spec/support/sendgo.rb
RSpec.configure do |config|
config.before do
Sendgo::Rails.reset!
allow(Sendgo::Rails).to receive(:client).and_return(fake_sendgo)
end
end
def fake_sendgo
@fake_sendgo ||= instance_double(
Sendgo::Client,
alimtalk: instance_double(Sendgo::AlimtalkService, send: { "message" => "Success" }),
brand_message: instance_double(Sendgo::BrandMessageService, send: { "message" => "Success" })
)
end
it "创建订单时发送通知消息" do
expect(fake_sendgo.alimtalk).to receive(:send).with(
hash_including(template_code: "ORDER_CONFIRM_001")
)
Order.create!(phone: "01012345678", number: "ORD-001")
end
不调用 reset! 的话,前一个用例记忆化的客户端会泄漏到下一个用例。
错误处理
begin
Sendgo::Rails.client.alimtalk.send(
template_code: "ORDER_CONFIRM_001",
contacts: [{ contact: "01012345678" }]
)
rescue Sendgo::SendgoError => e
case e.error_code
when "INVALID_ACCESS_KEY", "INVALID_SECRET_KEY"
Rails.logger.error("请检查 Sendgo 密钥")
when "PAYMENT_REQUIRED"
Rails.logger.error("Sendgo 余额不足")
when "IP_NOT_ALLOWED"
Rails.logger.error("该 IP 未在白名单中")
else
raise if e.status_code >= 500 # 临时故障,交给任务重试
Rails.logger.error("Sendgo #{e.status_code}: #{e.message}")
end
end
Sendgo::SendgoError 提供 status_code、error_code、endpoint、api_version、response_body。
请根据 error_code 分支,而不要匹配错误消息文本 —— 消息文案可能变更,错误代码才是契约。
TOKEN_EXPIRED 与 TOKEN_MISMATCH 已在核心 gem 内部处理:会重新签发令牌并自动重试该请求一次。
配置项
config.sendgo 键 |
环境变量 | 是否必填 | 默认值 | 说明 |
|---|---|---|---|---|
access_key |
SENDGO_ACCESS_KEY |
必填 | — | Sendgo 访问密钥 |
secret_key |
SENDGO_SECRET_KEY |
必填 | — | Sendgo 私密密钥 |
kakao_sender_key |
SENDGO_KAKAO_SENDER_KEY |
选填 | nil |
Kakao 发送者资料密钥 |
sms_sender_key |
SENDGO_SMS_SENDER_KEY |
选填 | nil |
短信主叫号码密钥 |
api_version |
SENDGO_API_VERSION |
选填 | "v2" |
API 版本(v1 | v2) |
url |
SENDGO_URL |
选填 | "https://sendgo.io" |
API 基础地址 |
短链接
短链接会缩短消息正文中的链接,并统计该链接是否被真正点击。 短信按字节计费,因此链接更短就意味着正文可以写更多内容。
仅 v2 支持。
再次缩短同一个原始 URL 会直接返回已有的链接。若希望按活动分别统计反应,
请使用 forceNew 生成新的短码。
deactivate 不会删除链接,只停止重定向。当已发送消息中的链接必须失效时使用它;
累计统计会保留,访问已停止的链接会返回 410 Gone。
created = Sendgo::Rails.client.short_url.create(
target_url: promotion_url(@promotion),
title: @promotion.name
)
code = created.dig("data", "code")
stats = Sendgo::Rails.client.short_url.stats(code)
stats 返回按日趋势(daily)以及按设备(byDevice)、来源(byReferer)、国家(byCountry)的分解。按日趋势读取的是预聚合表,因此点击量再大响应时间也保持稳定。
包信息
- 包名:
sendgo-rails(RubyGems) - 仓库:send-go/rails
- 注册表:https://rubygems.org/gems/sendgo-rails
- 许可:MIT
如何获取 API 密钥
登录 Sendgo 后,在 API/SDK → API 对接 菜单中签发访问密钥与私密密钥。
使用通知消息/好友消息需在 Kakao 渠道 登记发送者资料以获取 kakao_sender_key;使用短信需在 发送号码 菜单登记主叫号码。
이 패키지로 할 수 있는 것
Send a Kakao Alimtalk — PHP, Node.js, Python, Java, Go examples →
Send Kakao Alimtalk with an approved template code. Runnable code for Laravel, Node.js, Python, PHP, Java, Go, Ruby and .NET, plus every required field and why sends fail.
Send SMS, LMS and MMS in South Korea — code examples →
Send Korean SMS (90 bytes), LMS (long text) and MMS (with images) through Sendgo. Type selection, byte counting, verification-code patterns and advertising rules.