기업회원 신청 서류 안내
신청자 구분에 따라 재직증명서 또는 위임장을 함께 제출해 주세요.
신청자 구분에 따라 재직증명서 또는 위임장을 함께 제출해 주세요.
Ruby / SDK REFERENCE
The official Rails integration for sending Kakao Alimtalk, Brand Message and SMS — a Railtie-configured client with ENV fallback.
bundle add sendgo-railsThe official Rails integration for sending Kakao Alimtalk, Brand Message and SMS
sendgo-rails wraps the sendgo core gem with a Railtie: it adds a config.sendgo namespace, falls back to environment variables, and exposes a memoised client as Sendgo::Rails.client.
# Gemfile
gem "sendgo-rails"
bundle install
bin/rails g sendgo:install
The generator writes config/initializers/sendgo.rb. The core sendgo gem comes along as a dependency.
Requires Ruby 3.1+ and Rails 6.1 or newer (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
Every setting resolves in two steps: config.sendgo.<key> first, then the matching environment variable. Leaving a value nil in the initializer is therefore the same as not setting it — the ENV value wins. That means you can drop the initializer entirely and configure the gem with environment variables alone.
Use Rails credentials instead of ENV if you prefer:
config.access_key = Rails.application.credentials.dig(:sendgo, :access_key)
Note that api_version defaults to v2 in the Rails integration (the bare Ruby core defaults to v1).
Sendgo::Rails.client.alimtalk.send(
template_code: "ORDER_CONFIRM_001",
contacts: [{ contact: "01012345678", var1: "ORD-001" }]
)
Sendgo::Rails.client is memoised and lazy — nothing is built until the first call, so requiring the gem does not read your configuration at boot. Every channel from the core gem is available on it:
| Method | Channel |
|---|---|
client.alimtalk |
Kakao Alimtalk |
client.friendtalk |
Kakao Friendtalk |
client.brand_message |
Kakao Brand Message (v2 only) |
client.sms |
SMS / LMS / MMS |
Because the client is memoised, changing config.sendgo at runtime has no effect until you call Sendgo::Rails.reset!.
Calling Sendgo::Rails.client from controllers scatters template codes through the app. A thin object keeps them in one place and gives you something to stub in tests:
# 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
Friendtalk was discontinued on 2025-12-31. Since 2026-01-01 Kakao delivers Friendtalk requests as Brand Message (free-form) automatically.
friendtalkstill works and is still the only path for free-formFT/FI/FWto individual recipients — use Brand Message for template-based rich types (FL/FC/FM/FP/FA), non-friend targeting (N/I) and broadcasts (F). Brand Message is the successor channel to Friendtalk: it reaches recipients who are not channel friends (targeting: "N") and can broadcast to every consenting channel friend (targeting: "F"). Message types map one-to-one with Friendtalk (FT→BT,FI→BI,FW→BW,FL→BL,FC→BC,FM→BM,FP→BP,FA→BA) — pass the Friendtalk code and the server converts it.
v2 only, which is the Rails integration's default.
client = Sendgo::Rails.client
# Single send — targeting M/N/I requires `contacts`
client.brand_message.send(
targeting: "M",
message_type: "FL",
friend_template_uuid: "9cd5460b-6458-4edc-9b11-c26d3013c340",
contacts: [{ contact: "01012345678", var1: "29,000 KRW" }]
)
# Broadcast — every consenting channel friend, no recipient list
result = client.brand_message.broadcast(
message_type: "FW",
friend_template_uuid: "9cd5460b-6458-4edc-9b11-c26d3013c340"
)
# A broadcast is asynchronous upstream, so poll for progress
client.brand_message.campaign(result.dig("data", "campaignId"))
client.brand_message.campaigns(from: "2026-08-01", count: 10)
friend_template_uuid is a required keyword argument on send; message_type defaults to "FT" and targeting to "M". broadcast is send with targeting forced to "F", so it accepts the same arguments.
Send after the transaction commits — a callback that fires inside the transaction still delivers the message if a later validation rolls the record back:
class Order < ApplicationRecord
after_commit :notify_customer, on: :create
private
def notify_customer
OrderConfirmJob.perform_later(id)
end
end
Sending is a network call, so keep it out of the request cycle:
# app/jobs/order_confirm_job.rb
class OrderConfirmJob < ApplicationJob
queue_as :notifications
# 5xx is transient; a 4xx will not succeed on retry.
# `:polynomially_longer` needs Rails 7.1+; on 6.1–7.0 use `: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 with a block runs the block after the attempts are exhausted. If you want to stop immediately on a 4xx, rescue inside perform and call discard_on instead:
discard_on Sendgo::SendgoError do |_job, error|
Rails.logger.error("Dropped: Sendgo #{error.error_code}")
end
# lib/tasks/promo.rake
namespace :promo do
desc "Broadcast the current promotion to every consenting channel friend"
task broadcast: :environment do
result = Sendgo::Rails.client.brand_message.broadcast(
message_type: "FW",
friend_template_uuid: "9cd5460b-6458-4edc-9b11-c26d3013c340"
)
puts "Accepted: #{result.dig('data', 'campaignId')}"
end
end
reset! drops the memoised client, which is what makes a stubbed client stick:
# 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 "sends an alimtalk when an order is created" do
expect(fake_sendgo.alimtalk).to receive(:send).with(
hash_including(template_code: "ORDER_CONFIRM_001")
)
Order.create!(phone: "01012345678", number: "ORD-001")
end
Without reset!, a client memoised by an earlier example leaks into the next one.
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("Check the Sendgo API keys")
when "PAYMENT_REQUIRED"
Rails.logger.error("Out of Sendgo credit")
when "IP_NOT_ALLOWED"
Rails.logger.error("IP is not allow-listed")
else
raise if e.status_code >= 500 # transient — let the job retry
Rails.logger.error("Sendgo #{e.status_code}: #{e.message}")
end
end
Sendgo::SendgoError exposes status_code, error_code, endpoint, api_version and response_body. Branch on error_code, not on the message text — messages can change, codes are the contract.
TOKEN_EXPIRED and TOKEN_MISMATCH are handled inside the core gem: the token is reissued and the request retried once.
config.sendgo key |
Environment variable | Required | Default | Description |
|---|---|---|---|---|
access_key |
SENDGO_ACCESS_KEY |
required | — | Sendgo access key |
secret_key |
SENDGO_SECRET_KEY |
required | — | Sendgo secret key |
kakao_sender_key |
SENDGO_KAKAO_SENDER_KEY |
optional | nil |
Kakao sender profile key |
sms_sender_key |
SENDGO_SMS_SENDER_KEY |
optional | nil |
SMS caller ID key |
api_version |
SENDGO_API_VERSION |
optional | "v2" |
API version (v1 | v2) |
url |
SENDGO_URL |
optional | "https://sendgo.io" |
API base URL |
Short URLs shrink the links in your message body and count whether they were actually clicked. SMS is billed by byte, so a shorter link leaves more room for copy.
v2 only.
Shortening the same target URL again returns the existing link. Pass forceNew
to mint a new code when you want per-campaign reaction figures kept separate.
deactivate does not delete the link — it only stops the redirect. Use it when a link
in an already-sent message has to be killed; the accumulated stats stay, and visitors
to a stopped link get 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 returns a daily series (daily) plus breakdowns by device (byDevice), referrer (byReferer) and country (byCountry). The daily series is read from a pre-aggregated table, so response time stays flat no matter how many clicks accumulate.
sendgo-rails (RubyGems)Sign in to Sendgo and open API/SDK → API integration to issue an access key and secret key.
Register a Kakao sender profile under Kakao channel to get your kakao_sender_key, and a caller ID under Sender numbers for SMS.
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 Korean SMS (90 bytes), LMS (long text) and MMS (with images) through Sendgo. Type selection, byte counting, verification-code patterns and advertising rules.