본문 바로가기
文档菜单

PHP / SDK REFERENCE

Laravel SDK 指南

用于发送 Kakao 通知消息、好友消息、品牌消息与 SMS 的官方 Laravel 扩展包 —— 门面、配置发布、队列友好。

이 문서의 목차
패키지
sendgo/laravel
언어
PHP
레지스트리
Packagist
설치
composer require sendgo/laravel

用于发送 Kakao 通知消息、品牌消息与短信的官方 Laravel 扩展包

sendgo/laravel 在 sendgo/php 核心之上提供 Laravel 集成:服务提供者自动发现、可发布的配置文件,以及 Sendgo 门面。

要求 PHP 8.2+ 与 Laravel 10/11。


安装

composer require sendgo/laravel

服务提供者会被自动发现,无需手动注册。

发布配置文件

php artisan vendor:publish --tag=sendgo-config

配置

# .env
SENDGO_ACCESS_KEY=your_access_key
SENDGO_SECRET_KEY=your_secret_key
SENDGO_KAKAO_SENDER_KEY=your_kakao_sender_key
SENDGO_SMS_SENDER_KEY=your_sms_sender_key
SENDGO_API_VERSION=v2
<?php
// config/sendgo.php
return [
    'access_key'       => env('SENDGO_ACCESS_KEY'),
    'secret_key'       => env('SENDGO_SECRET_KEY'),
    'kakao_sender_key' => env('SENDGO_KAKAO_SENDER_KEY'),
    'sms_sender_key'   => env('SENDGO_SMS_SENDER_KEY'),
    'api_version'      => env('SENDGO_API_VERSION', 'v2'),
    'url'              => env('SENDGO_URL', 'https://sendgo.io'),
];

配置缓存过(php artisan config:cache)之后修改 .env 不会生效 —— 部署时请重新执行一次。


快速上手

<?php

use Sendgo\Laravel\Facades\Sendgo;

Sendgo::alimtalk()->send([
    'templateCode' => 'ORDER_CONFIRM_001',
    'contacts'     => [
        ['contact' => '01012345678', 'name' => '洪吉童', 'var1' => 'ORD-001'],
    ],
]);

各发送渠道都是门面上的方法:

方法 渠道
Sendgo::alimtalk() Kakao 通知消息
Sendgo::friendtalk() Kakao 好友消息
Sendgo::brandMessage() Kakao 品牌消息(仅 v2)
Sendgo::sms() SMS / LMS / MMS

也可以直接注入核心客户端,这在依赖关系需要显式声明时更清晰:

<?php

use Sendgo\Php\Sendgo;

class OrderNotifier
{
    public function __construct(private Sendgo $sendgo) {}

    public function confirmed(string $phone, string $orderNo): void
    {
        // 注入客户端时,各渠道是属性而不是方法。
        $this->sendgo->alimtalk->send([
            'templateCode' => 'ORDER_CONFIRM_001',
            'contacts'     => [['contact' => $phone, 'var1' => $orderNo]],
        ]);
    }
}

门面写作 Sendgo::alimtalk()(方法),注入的客户端写作 $sendgo->alimtalk(属性)。核心类同时支持两种写法,因此两边都可用。


通知消息

<?php

// 批量发送
Sendgo::alimtalk()->send([
    'templateCode' => 'ORDER_CONFIRM_001',
    'contacts'     => [
        ['contact' => '01011111111', 'var1' => 'ORD-001', 'var2' => '29,000元'],
        ['contact' => '01022222222', 'var1' => 'ORD-002', 'var2' => '15,000元'],
    ],
]);

// 预约发送
Sendgo::alimtalk()->send([
    'templateCode' => 'PROMO_SUMMER_2026',
    'scheduleType' => 'SCHEDULED',
    'at'           => '2026-07-28 09:00:00',
    'contacts'     => [['contact' => '01012345678', 'var1' => '夏季限定 5 折']],
]);

// 失败时自动回退为短信
Sendgo::alimtalk()->send([
    'templateCode' => 'DELIVERY_START_001',
    'replaceSms'   => 'Y',
    'smsSubject'   => '[发货通知]',
    'smsContent'   => '您购买的商品已出库。',
    'contacts'     => [['contact' => '01012345678', 'var1' => 'ORD-001']],
]);

好友消息

⚠️ 已停用 —— 按 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。

<?php

Sendgo::friendtalk()->send([
    'content'  => '7 月限时特惠开始了,欢迎查看。',
    'contacts' => [['contact' => '01012345678']],
]);

品牌消息

品牌消息是好友消息的后继渠道:可触达非频道好友的接收者('targeting' => 'N'),也可向已同意接收的全部频道好友群发('targeting' => 'F')。消息类型与好友消息一一对应(FT→BT、FI→BI、FW→BW、FL→BL、FC→BC、FM→BM、FP→BP、FA→BA)—— 传入好友消息的代码,服务端会自动转换。

仅 v2 支持。请设置 SENDGO_API_VERSION=v2。

<?php

// 单条发送 —— targeting 为 M/N/I 时必须提供 contacts
Sendgo::brandMessage()->send([
    'targeting'          => 'M',
    'messageType'        => 'FL',
    'friendTemplateUuid' => '9cd5460b-6458-4edc-9b11-c26d3013c340',
    'contacts'           => [['contact' => '01012345678', 'var1' => '29,000元']],
]);

// 群发 —— 已同意接收的全部频道好友(不传 contacts)
$result = Sendgo::brandMessage()->broadcast([
    'messageType'        => 'FW',
    'friendTemplateUuid' => '9cd5460b-6458-4edc-9b11-c26d3013c340',
]);

// 群发在上游为异步处理,需轮询查看进度
Sendgo::brandMessage()->campaign($result['data']['campaignId']);
Sendgo::brandMessage()->campaigns(['from' => '2026-08-01', 'count' => 10]);

群发可能触达整个好友列表,请务必从明确的管理操作触发(Artisan 命令或受权限保护的路由),不要放在公开路由上。


短信 / 长短信 / 多媒体短信

<?php

Sendgo::sms()->sendSms([
    'content'  => '[Sendgo] 验证码:123456(请在 5 分钟内输入)',
    'contacts' => [['contact' => '01012345678']],
]);

Sendgo::sms()->sendLms([
    'subject'  => '[重要] 服务维护通知',
    'content'  => '服务将于 2026-07-25 02:00 ~ 06:00 进行维护。',
    'contacts' => [['contact' => '01012345678']],
]);

Sendgo::sms()->sendMms([
    'subject'  => '[活动] 7 月特惠',
    'content'  => '欢迎查看本月特价商品。',
    'contacts' => [['contact' => '01012345678']],
]);

队列发送

发送是一次外发 HTTP 调用,请不要放在请求生命周期里:

<?php
// app/Jobs/SendOrderConfirm.php

namespace App\Jobs;

use Illuminate\Contracts\Queue\ShouldQueue;
use Illuminate\Foundation\Bus\Dispatchable;
use Illuminate\Queue\InteractsWithQueue;
use Sendgo\Php\Exception\SendgoException;
use Sendgo\Php\Sendgo;

class SendOrderConfirm implements ShouldQueue
{
    use Dispatchable, InteractsWithQueue;

    public int $tries = 3;

    public function __construct(
        private string $phone,
        private string $orderNo,
    ) {}

    public function handle(Sendgo $sendgo): void
    {
        try {
            $sendgo->alimtalk->send([
                'templateCode' => 'ORDER_CONFIRM_001',
                'contacts'     => [['contact' => $this->phone, 'var1' => $this->orderNo]],
            ]);
        } catch (SendgoException $e) {
            // 4xx 重试也不会成功,直接标记失败并记录原因。
            if ($e->getStatusCode() < 500) {
                $this->fail($e);

                return;
            }

            throw $e;   // 5xx 为临时故障,交给队列重试
        }
    }

    /** 5xx 重试的退避间隔(秒) */
    public function backoff(): array
    {
        return [10, 60, 300];
    }
}

对 4xx 调用 fail() 是关键:否则一个错误的模板代码会耗尽全部重试次数,看起来像临时故障。

事务提交后再发送

在事务内派发任务,可能出现事务回滚了但消息已经发出去的情况:

<?php

use Illuminate\Support\Facades\DB;

DB::transaction(function () use ($order) {
    $order->save();

    // 事务提交后才入队
    DB::afterCommit(fn () => SendOrderConfirm::dispatch($order->phone, $order->number));
});

如果队列连接配置了 after_commit => true,则所有任务默认就是提交后派发。


异常处理

<?php

use Sendgo\Php\Exception\SendgoException;

try {
    Sendgo::alimtalk()->send([...]);
} catch (SendgoException $e) {
    Log::error('Sendgo 发送失败', [
        'status'     => $e->getStatusCode(),
        'error_code' => $e->getErrorCode(),
        'endpoint'   => $e->getEndpoint(),
    ]);

    match ($e->getErrorCode()) {
        'INVALID_ACCESS_KEY',
        'INVALID_SECRET_KEY'    => report(new \RuntimeException('请检查 Sendgo 密钥')),
        'IP_NOT_ALLOWED'        => report(new \RuntimeException('该 IP 未在白名单中')),
        'PAYMENT_REQUIRED'      => report(new \RuntimeException('Sendgo 余额不足')),
        'INVALID_TEMPLATE_CODE' => Log::warning('模板不存在'),
        default                 => null,
    };
}

请根据 getErrorCode() 分支,而不要匹配错误消息文本 —— 消息文案可能变更,错误代码才是契约。 TOKEN_EXPIRED 与 TOKEN_MISMATCH 已在核心 SDK 内部处理:会重新签发令牌并自动重试该请求一次。


测试

门面自带替身支持:

<?php

use Sendgo\Laravel\Facades\Sendgo;

public function test_order_creation_sends_alimtalk(): void
{
    // 也可以直接把核心客户端换成 mock 绑定到容器:
    $this->instance(\Sendgo\Php\Sendgo::class, $fake = \Mockery::mock(\Sendgo\Php\Sendgo::class));

    $fake->shouldReceive('alimtalk->send')->once();

    $this->post('/orders', ['phone' => '01012345678'])->assertCreated();
}

使用队列时,Queue::fake() 之后断言 SendOrderConfirm::class 已被派发会更简单,也不必碰 SDK。


配置项

键 环境变量 是否必填 默认值 说明
access_key SENDGO_ACCESS_KEY 必填 — Sendgo 访问密钥
secret_key SENDGO_SECRET_KEY 必填 — Sendgo 私密密钥
kakao_sender_key SENDGO_KAKAO_SENDER_KEY 选填 null Kakao 发送者资料密钥
sms_sender_key SENDGO_SMS_SENDER_KEY 选填 null 短信主叫号码密钥
api_version SENDGO_API_VERSION 选填 v2 API 版本(v1 | v2)
url SENDGO_URL 选填 https://sendgo.io API 基础地址

短链接

短链接会缩短消息正文中的链接,并统计该链接是否被真正点击。 短信按字节计费,因此链接更短就意味着正文可以写更多内容。

仅 v2 支持。

再次缩短同一个原始 URL 会直接返回已有的链接。若希望按活动分别统计反应, 请使用 forceNew 生成新的短码。

deactivate 不会删除链接,只停止重定向。当已发送消息中的链接必须失效时使用它; 累计统计会保留,访问已停止的链接会返回 410 Gone。

use Sendgo\Laravel\Facades\Sendgo;

$short = Sendgo::shortUrl()->create([
    'targetUrl' => 'https://example.com/promotions/summer-sale',
    'title'     => '夏季促销落地页',
]);

$link = $short['data']['shortUrl'];
$code = $short['data']['code'];

$stats = Sendgo::shortUrl()->stats($code, ['from' => '2026-08-01']);
Sendgo::shortUrl()->deactivate($code);

stats 返回按日趋势(daily)以及按设备(byDevice)、来源(byReferer)、国家(byCountry)的分解。按日趋势读取的是预聚合表,因此点击量再大响应时间也保持稳定。


包信息

  • 包名:sendgo/laravel(Packagist)
  • 仓库:send-go/laravel
  • 注册表:https://packagist.org/packages/sendgo/laravel
  • 许可:MIT

如何获取 API 密钥

登录 Sendgo 后,在 API/SDK → API 对接 菜单中签发访问密钥与私密密钥。 使用通知消息/好友消息需在 Kakao 渠道 登记发送者资料以获取 kakao_sender_key;使用短信需在 发送号码 菜单登记主叫号码。

이 패키지로 할 수 있는 것

관련 패키지

专注构建,消息交给 Sendgo。返回顶部 ↑