기업회원 신청 서류 안내
신청자 구분에 따라 재직증명서 또는 위임장을 함께 제출해 주세요.
신청자 구분에 따라 재직증명서 또는 위임장을 함께 제출해 주세요.
Dart / SDK REFERENCE
用于发送 Kakao 通知消息、好友消息、品牌消息与 SMS 的官方 Dart SDK —— 仅限服务端使用。
dart pub add sendgo_flutter用于发送 Kakao 通知消息、品牌消息与短信的官方 Dart SDK
sendgo_flutter 是用于调用 Sendgo API 的 Dart 客户端。
⚠️ 仅限服务端使用。 访问密钥与私密密钥绝不可打包进 Flutter 应用 —— 已发布的应用包可被反编译并提取出密钥,从而被他人用你的账户任意发送消息。请只在 Dart 后端(Shelf、Serverpod、Dart Frog、Cloud Functions 等)中使用本 SDK,让 Flutter 应用调用你自己的服务端接口。
dart pub add sendgo_flutter
import 'dart:io';
import 'package:sendgo_flutter/sendgo_flutter.dart';
final sendgo = SendgoClient(
accessKey: Platform.environment['SENDGO_ACCESS_KEY']!,
secretKey: Platform.environment['SENDGO_SECRET_KEY']!,
kakaoSenderKey: Platform.environment['SENDGO_KAKAO_SENDER_KEY'],
smsSenderKey: Platform.environment['SENDGO_SMS_SENDER_KEY'],
apiVersion: 'v2',
);
await sendgo.alimtalk.send(AlimtalkRequest(
templateCode: 'ORDER_CONFIRM_001',
contacts: [Contact(contact: '01012345678', name: '洪吉童', var1: 'ORD-001')],
));
各发送渠道都是客户端上的属性:
| 属性 | 渠道 |
|---|---|
sendgo.alimtalk |
Kakao 通知消息 |
sendgo.friendtalk |
Kakao 好友消息 |
sendgo.brandMessage |
Kakao 品牌消息(仅 v2) |
sendgo.sms |
SMS / LMS / MMS |
apiVersion 的默认值为 'v1',品牌消息需要显式设为 'v2'。
请创建一次客户端并复用(例如顶层 final),令牌缓存才能生效。
// 批量发送
await sendgo.alimtalk.send(AlimtalkRequest(
templateCode: 'ORDER_CONFIRM_001',
contacts: [
Contact(contact: '01011111111', var1: 'ORD-001', var2: '29,000元'),
Contact(contact: '01022222222', var1: 'ORD-002', var2: '15,000元'),
],
));
// 预约发送
await sendgo.alimtalk.send(AlimtalkRequest(
templateCode: 'PROMO_SUMMER_2026',
scheduleType: 'SCHEDULED',
at: '2026-07-28 09:00:00',
contacts: [Contact(contact: '01012345678', var1: '夏季限定 5 折')],
));
// 失败时自动回退为短信
await sendgo.alimtalk.send(AlimtalkRequest(
templateCode: 'DELIVERY_START_001',
replaceSms: 'Y',
smsSubject: '[发货通知]',
smsContent: '您购买的商品已出库。',
contacts: [Contact(contact: '01012345678', var1: 'ORD-001')],
));
templateCode 与 contacts 是 required 命名参数,遗漏时编译期即报错。
Contact 支持 var1 ~ var8,以及任意命名变量的 variables。
⚠️ 已停用 —— 按 Kakao 政策,好友消息已于 2025-12-31 停止服务。 自 2026-01-01 起,好友消息的发送请求由 Kakao 侧自动改以**品牌消息(自由形式)**发出。 调用仍会成功;而且自由文本类型(
FT/FI/FW)发往单个接收者的路径目前仍只有这一条, 因此现有代码无需立即改动。以下情形请改用品牌消息:
- 基于模板的富文本类型(
FL/FC/FM/FP/FA)- 非频道好友的接收者(
targeting=N/I)- 向已同意接收的全部频道好友群发(
targeting=F)消息类型一一对应,转换由服务端处理 ——
FT→BT、FI→BI、FW→BW、FL→BL、FC→BC、FM→BM、FP→BP、FA→BA。
// 文本型
await sendgo.friendtalk.send(FriendtalkRequest(
content: '7 月限时特惠开始了,欢迎查看。',
contacts: [Contact(contact: '01012345678')],
));
// 图片型
await sendgo.friendtalk.send(FriendtalkRequest(
messageType: 'FI',
content: '本周特价商品',
imageUrl: 'https://cdn.example.com/banner.jpg',
imageLink: 'https://example.com/event',
contacts: [Contact(contact: '01012345678')],
));
品牌消息是好友消息的后继渠道:可触达非频道好友的接收者(targeting: 'N'),也可向已同意接收的全部频道好友群发(targeting: 'F')。消息类型与好友消息一一对应(FT→BT、FI→BI、FW→BW、FL→BL、FC→BC、FM→BM、FP→BP、FA→BA)—— 传入好友消息的代码,服务端会自动转换。
仅 v2 支持。请设置
apiVersion: 'v2'。
// 单条发送 —— targeting 为 M/N/I 时必须提供 contacts
final result = await sendgo.brandMessage.send(BrandMessageRequest(
targeting: 'M',
messageType: 'FL',
friendTemplateUuid: '9cd5460b-6458-4edc-9b11-c26d3013c340',
contacts: [Contact(contact: '01012345678', var1: '29,000元')],
));
// 群发 —— 已同意接收的全部频道好友(不传 contacts)
final accepted = await sendgo.brandMessage.broadcast(BrandMessageRequest(
messageType: 'FW',
friendTemplateUuid: '9cd5460b-6458-4edc-9b11-c26d3013c340',
));
// 群发在上游为异步处理,需轮询查看进度
await sendgo.brandMessage.campaign(accepted['data']['campaignId'] as String);
await sendgo.brandMessage.campaigns(from: '2026-08-01', count: 10);
friendTemplateUuid 是 required;targeting 默认为 'M',messageType 默认为 'FT'。
broadcast 内部调用 request.asBroadcast(),即把 targeting 换成 'F' 后再发送,因此两者接受相同的请求对象。
targeting 的取值含义:
| 值 | 含义 |
|---|---|
M |
频道好友中的指定接收者 |
N |
非频道好友的接收者 |
I |
按标识符指定的接收者 |
F |
已同意接收的全部频道好友(群发) |
// SMS(90 字节以内)
await sendgo.sms.sendSms(SmsRequest(
content: '[Sendgo] 验证码:123456(请在 5 分钟内输入)',
contacts: [Contact(contact: '01012345678')],
));
// LMS(长文,2,000 字节以内)
await sendgo.sms.sendLms(SmsRequest(
subject: '[重要] 服务维护通知',
content: '服务将于 2026-07-25 02:00 ~ 06:00 进行维护。',
contacts: [Contact(contact: '01012345678')],
));
// MMS(含图片)
await sendgo.sms.sendMms(SmsRequest(
subject: '[活动] 7 月特惠',
content: '欢迎查看本月特价商品。',
contacts: [Contact(contact: '01012345678')],
));
sendSms / sendLms / sendMms 会分别把 messageType 固定为 SMS / LMS / MMS,因此即使请求对象里写了别的类型也不会发错。
Flutter 应用调用你自己的接口,密钥留在服务端 —— 以 Dart Frog 为例:
// routes/notify.dart
import 'dart:io';
import 'package:dart_frog/dart_frog.dart';
import 'package:sendgo_flutter/sendgo_flutter.dart';
// 顶层创建一次,令牌缓存跨请求复用。
final _sendgo = SendgoClient(
accessKey: Platform.environment['SENDGO_ACCESS_KEY']!,
secretKey: Platform.environment['SENDGO_SECRET_KEY']!,
kakaoSenderKey: Platform.environment['SENDGO_KAKAO_SENDER_KEY'],
apiVersion: 'v2',
);
Future<Response> onRequest(RequestContext context) async {
if (context.request.method != HttpMethod.post) {
return Response(statusCode: HttpStatus.methodNotAllowed);
}
final body = await context.request.json() as Map<String, dynamic>;
try {
await _sendgo.alimtalk.send(AlimtalkRequest(
templateCode: 'ORDER_CONFIRM_001',
contacts: [Contact(contact: body['phone'] as String, var1: body['orderNo'] as String)],
));
return Response(statusCode: HttpStatus.accepted);
} on SendgoException catch (e) {
// 上游细节记录到日志,对外只返回通用状态。
print('Sendgo ${e.statusCode} [${e.errorCode}]: ${e.message}');
return Response(
statusCode: e.statusCode >= 500 ? HttpStatus.badGateway : HttpStatus.badRequest,
);
}
}
try {
await sendgo.alimtalk.send(request);
} on SendgoException catch (e) {
print('Sendgo ${e.statusCode} [${e.errorCode}] ${e.endpoint}: ${e.message}');
switch (e.errorCode) {
case 'INVALID_ACCESS_KEY':
case 'INVALID_SECRET_KEY':
// 是我们的配置有误,而非调用方的请求有误。
alertOps('请检查 Sendgo 密钥');
case 'IP_NOT_ALLOWED':
alertOps('该 IP 未在白名单中');
case 'PAYMENT_REQUIRED':
alertOps('Sendgo 余额不足');
default:
// 5xx 为临时故障,可重试;4xx 重试不会成功。
if (e.statusCode >= 500) rethrow;
}
}
SendgoException 提供 statusCode、errorCode、endpoint、apiVersion、responseBody。
请根据 errorCode 分支,而不要匹配错误消息文本 —— 消息文案可能变更,错误代码才是契约。
TOKEN_EXPIRED 与 TOKEN_MISMATCH 已在 SDK 内部处理:会重新签发令牌并自动重试该请求一次。
| 命名参数 | 是否必填 | 默认值 | 说明 |
|---|---|---|---|
accessKey |
必填 | — | Sendgo 访问密钥 |
secretKey |
必填 | — | Sendgo 私密密钥 |
kakaoSenderKey |
选填 | null |
Kakao 发送者资料密钥 |
smsSenderKey |
选填 | null |
短信主叫号码密钥 |
apiVersion |
选填 | 'v1' |
API 版本(v1 | v2) |
baseUrl |
选填 | 'https://sendgo.io' |
API 基础地址 |
短链接会缩短消息正文中的链接,并统计该链接是否被真正点击。 短信按字节计费,因此链接更短就意味着正文可以写更多内容。
仅 v2 支持。
再次缩短同一个原始 URL 会直接返回已有的链接。若希望按活动分别统计反应,
请使用 forceNew 生成新的短码。
deactivate 不会删除链接,只停止重定向。当已发送消息中的链接必须失效时使用它;
累计统计会保留,访问已停止的链接会返回 410 Gone。
final created = await sendgo.shortUrl.create(const ShortUrlRequest(
targetUrl: 'https://example.com/promotions/summer-sale',
title: '夏季促销落地页',
));
final code = created['data']['code'] as String;
final link = created['data']['shortUrl'] as String;
// 反应统计 —— 按日趋势 + 设备/来源/国家分解
final stats = await sendgo.shortUrl.stats(code, from: '2026-08-01');
await sendgo.shortUrl.list(count: 10);
await sendgo.shortUrl.show(code);
await sendgo.shortUrl.deactivate(code); // 仅停止重定向,统计保留
stats 返回按日趋势(daily)以及按设备(byDevice)、来源(byReferer)、国家(byCountry)的分解。按日趋势读取的是预聚合表,因此点击量再大响应时间也保持稳定。
sendgo_flutter(pub.dev)登录 Sendgo 后,在 API/SDK → API 对接 菜单中签发访问密钥与私密密钥。
使用通知消息/好友消息需在 Kakao 渠道 登记发送者资料以获取 kakaoSenderKey;使用短信需在 发送号码 菜单登记主叫号码。
From issuing an access key to sending a Kakao Alimtalk, with working code in Node.js, Python, PHP, Laravel, Java and Go.
Pick the organisation, issue API keys, register sender numbers and templates from a coding agent. Everything except topping up credit works without the console.
Kakao Alimtalk, Kakao Brand Message and SMS/LMS/MMS differ in what content they allow, what they cost and what you must set up first. Which to pick, by situation.
Pick the right Sendgo package for PHP, Laravel, Symfony, WordPress, Node.js, Next.js, NestJS, Python, Django, FastAPI, Java, Spring Boot, Go, Ruby, Rails, .NET, ASP.NET Core or Flutter.
Exchange an accessKey and secretKey for a bearer token, and call the Sendgo API with it. Differences between v1 and v2, token caching, and the 401/403 codes.
Korean law requires the caller ID to be pre-registered. How to register an SMS sending number and connect a Kakao channel, and where registrations usually get rejected.