文档菜单
Dart / SDK REFERENCE
Flutter / Dart SDK 指南
用于发送 Kakao 通知消息、好友消息、品牌消息与 SMS 的官方 Dart SDK —— 仅限服务端使用。
이 문서의 목차
- 패키지
- sendgo_flutter
- 언어
- Dart
- 레지스트리
- pub.dev
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,因此即使请求对象里写了别的类型也不会发错。
在 Dart 后端中使用
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) - 仓库:send-go/flutter
- 注册表:https://pub.dev/packages/sendgo_flutter
- 许可:MIT
如何获取 API 密钥
登录 Sendgo 后,在 API/SDK → API 对接 菜单中签发访问密钥与私密密钥。
使用通知消息/好友消息需在 Kakao 渠道 登记发送者资料以获取 kakaoSenderKey;使用短信需在 发送号码 菜单登记主叫号码。
이 패키지로 할 수 있는 것
Send your first Kakao Alimtalk in 5 minutes →
From issuing an access key to sending a Kakao Alimtalk, with working code in Node.js, Python, PHP, Laravel, Java and Go.
Finish the Sendgo integration from your AI agent — MCP server and Account API →
Pick the organisation, issue API keys, register sender numbers and templates from a coding agent. Everything except topping up credit works without the console.
Alimtalk, Brand Message or SMS — choosing a messaging channel in Korea →
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.
Which Sendgo SDK should I install? — 20 official packages →
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.
Sendgo API authentication — access keys and bearer tokens →
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.
Registering a sending number in South Korea — required before you can send →
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.