闪闪编辑器支持第三方应用集成,您可以通过后端接口和前端嵌入的方式,来将闪闪编辑器集成到您自己的网站里。通过这种方式,您的用户可以无感知的在您的网站里使用闪闪编辑器来制作邮件。
新建邮件

编辑邮件

1、开通账号
点击 闪闪编辑器-应用申请,填写基本信息后,会有运营小妹儿和您联系,开通应用账号。
账号开通之后,点击 闪闪编辑器-应用管理,进入系统。
2、设置固定参数
品牌 logo:将您的网站 logo 显示在闪闪编辑器编辑界面的左上角。
如果不配置此项,将会默认显示闪闪编辑器的 logo <img width="120" src="https://www.shanedit.com/img/index_logo.fc9738f0.png"></img>
此参数在调用 /access/email 接口时也可以传入,以接口传入参数为准。
Push URL:您的用户所编辑的邮件内容会“实时”的推送给这个接口地址。由您进行鉴权(是否由闪闪推送)、校验(内容是否被篡改)之后解析并存储。
Push Key:闪闪会生成密钥对。在推送数据时,闪闪会用公钥加密,您使用私钥解密。
Return URL:您的用户编辑完邮件之后,点击“返回”按钮时,页面所跳转页面的路径。
未来还会增加编辑器界面 UI 的配色等配置项。
URL
xxxxxxxxxxpost https://www.shanedit.com/access/token
描述
在应用内创建用户,获取或更新用户token。
如果id不存在,则是新建用户、获取token;
如果id已存在,则是更新用户token。
用户创建邮件时,需要用对应 token 进行校验。
token 过期,重新获取即可。
参数说明
| 参数 | 分类 | 类型 | 必须 | 说明 |
|---|---|---|---|---|
| Authorization | header | string | 是 | base64($appid:$appkey) |
| Content-Type | header | string | 是 | application/json |
| data | body | json | 是 | 用户信息,见示例 |
示例
xxxxxxxxxxcurl -X POST "https://www.shanedit.com/access/token/" \-H "Authorization: base64($appid:$appkey)" \-H "Content-Type: application/json" \--data '{"id": "00240","name": "user_test01","email": "user_test01@sendcloud.net","phone": "13477778888"}'id: 必选,是用户的唯一标识, 不能包含:,/,?,#,[,],@,!,$,&,',(,),*,+,,,;,= 其中任意一种特殊字符name: 可选;用户名称email: 可选;用户邮箱phone: 可选;用户手机号* 如果id不存在,则闪闪会按照参数,创建新用户,返回token* 如果id已存在,则闪闪会忽略name,email,phone等字段,只返回已存在用户的信息和新token
返回值示例
xxxxxxxxxx{"data": {"expireTime": "2021-10-15 18:01:08","createTime": "2021-10-08 18:04:39","id": "00240","name": "user_test01","email": "user_test01@sendcloud.net","phone": "13477778888","token": "c41ab1a4-d728-4c1f-954c-8d823769c951"},"message": "user login success","success": true,"code": 200}expireTime: 有效期默认为7天id: 回传参数name: 回传参数,如果为空,系统会生成默认值;如果id已存在,返回已存在用户的nameemail: 回传参数;如果id已存在,返回已存在用户的namephone: 回传参数;如果id已存在,返回已存在用户的name
URL
xxxxxxxxxxpost https://www.shanedit.com/access/code
描述
为前端访问获取临时 code
使用一次即失效,有效期5分钟
参数说明
| 参数 | 分类 | 类型 | 必须 | 说明 |
|---|---|---|---|---|
| Authorization | header | string | 是 | Bearer $token |
| Content-Type | header | string | 是 | application/json |
示例
xxxxxxxxxxcurl -X POST "https://www.shanedit.com/access/code/" \-H "Authorization: Bearer $token" \-H "Content-Type: application/json"
返回值示例
xxxxxxxxxx{"data": "Clk9YUsQbgU2141iV1o8SDf0fjwipTk1","message": "obtained code success","success": true,"code": 200}data: 临时code
URL
xxxxxxxxxxpost https://www.shanedit.com/access/email
描述
创建邮件模板
参数说明
| 参数 | 分类 | 类型 | 必须 | 说明 |
|---|---|---|---|---|
| Authorization | header | string | 是 | Bearer $token |
| Content-Type | header | string | 是 | application/json |
| data | body | json | 是 | 邮件模板信息,见示例 |
示例
xxxxxxxxxxcurl -X POST "https://www.shanedit.com/access/email/" \-H "Authorization: Bearer $token" \-H "Content-Type: application/json" \--data '{"name": "会员30天唤醒邮件1号模板","extra": {"user_tag": "母婴、化妆品","user_location": "wuhan"}}'name: 必选extra: 可选
返回值示例
xxxxxxxxxx{"data": {"createTime": "2021-10-12 19:24:51","extra": {"user_tag": "母婴、化妆品","user_location": "wuhan"},"name": "会员30天唤醒邮件1号模板","id": "ss_1634037878869"},"message": "create email success","success": true,"code": 200}id:邮件id
URL
xxxxxxxxxxget https://www.shanedit.com/access/email/{id}
描述
查询单个邮件模板详情
参数说明
| 参数 | 分类 | 类型 | 必须 | 说明 |
|---|---|---|---|---|
| Authorization | header | string | 是 | Bearer $token |
示例
xxxxxxxxxxcurl -X GET "https://www.shanedit.com/access/email/250305" \-H "Authorization: Bearer $token" \
返回值示例
xxxxxxxxxx{"data": {"userId":1,"html":'<!doctype html><html lang="en" xmlns="http://www.w3.org/1999/xhtml" xmlns:v="urn:schemas-microsoft-com:vml" xmlns:o="urn:schemas-microsoft-com:office:office"><head><title></title></head><body>template html source code</body><html>',"id":250305,"name":"邮件模板名称","settings":'{"type":"root","data":{"bgColor":"#f8f9fa","contColor":"#ffffff"},"placeholders":[],"width":800,"height":457}',"snapshot":"https://www.shanedit.com/snapshots/f6a977c15c1e5ec0785d6f33650ed7dc.png","subject":"邮件模板主题","summary":"邮件模板摘要","updateTime":"2025-02-26 15:35:23","createTime":"2025-02-26 15:35:23"},"message": " success","success": true,"code": 200}
URL
xxxxxxxxxxdelete https://www.shanedit.com/access/email/{id}
描述
删除邮件模板
参数说明
| 参数 | 分类 | 类型 | 必须 | 说明 |
|---|---|---|---|---|
| Authorization | header | string | 是 | Bearer $token |
示例
xxxxxxxxxxcurl -X DELETE "https://www.shanedit.com/access/email/250305" \-H "Authorization: Bearer $token" \
返回值示例
xxxxxxxxxx{"data": {},"message": "delete success","success": true,"code": 200}
URL
xxxxxxxxxxput https://www.shanedit.com/access/email/{id}
描述
修改邮件模板,只支持修改模板名称、模板主题
参数说明
| 参数 | 分类 | 类型 | 必须 | 说明 |
|---|---|---|---|---|
| Authorization | header | string | 是 | Bearer $token |
| Content-Type | header | string | 是 | application/json |
| data | body | json | 是 | 邮件模板信息,见示例 |
示例
xxxxxxxxxxcurl -X put "https://www.shanedit.com/access/email/77067" \-H "Authorization: Bearer $token" \-H "Content-Type: application/json" \--data '{"subject":"会员唤醒2","name":"召回2"}'name: 可选subject:可选
返回值示例
xxxxxxxxxx{"data": {"subject": "会员唤醒2","name": "召回2","id": 7706},"message": "update success","success": true,"code": 200}id:邮件id
URL
xxxxxxxxxxpost https://www.shanedit.com/access/email/copy
描述
复制邮件模板
参数说明
| 参数 | 分类 | 类型 | 必须 | 说明 |
|---|---|---|---|---|
| Authorization | header | string | 是 | Bearer $token |
| Content-Type | header | string | 是 | application/j |
| data | body | json | 是 | 邮件模板信息,见示例 |
示例
xxxxxxxxxxcurl -X POST "https://www.shanedit.com/access/email/copy" \-H "Authorization: Bearer $token" \-H "Content-Type: application/json" \--data '{"id": "ss_1634037878869","name": "会员30天唤醒邮件2号模板","extra": {"user_tag": "母婴、化妆品","user_location": "wuhan"}}'id: 必选;想要复制的原邮件idname: 可选;复制出的新邮件的名称
返回值示例
xxxxxxxxxx{"data": {"createTime": "2021-10-12 19:24:51","extra": {"user_tag": "母婴、化妆品","user_location": "wuhan"}"name": "会员30天唤醒邮件2号模板","id": "ss_1634037878870"},"message": "copy email success","success": true,"code": 200}id:复制的新邮件的邮件idname:回传参数,如果为空,系统会生成默认值
URL
xxxxxxxxxxget https://www.shanedit.com/thirdApp
描述
在您的网站前端调用,跳转到闪闪编辑器,开始编辑邮件
参数说明
| 参数 | 分类 | 类型 | 必须 | 说明 |
|---|---|---|---|---|
| code | query | string | 是 | 临时code: $code |
| id | query | string | 是 | 邮件id: $id |
| lang | query | string | 否 | 语言参数lang: $lang 支持的值: zh_CN,zh_TW, en_US, th_TH, ja_JP |
示例
通过 Javascript 事件打开新标签页
xxxxxxxxxx<script src="" type="text/javascript">document.querySelector("#{your html button id}).onclick = function() {window.open('https://www.shanedit.com/thirdApp?code=$code&id=$id&lang=$lang');}</script>
通过 a 标签方式
xxxxxxxxxx<a href="https://www.shanedit.com/thirdApp?code=$code&id=$id&lang=$lang" target="_blank">编辑邮件</a>
通过 Iframe 内嵌方式
xxxxxxxxxx<iframe src="https://www.shanedit.com/thirdApp?code=$code&id=$id&lang=$lang" frameborder="0"></iframe>
URL
xxxxxxxxxxpost $PushURL
描述
推送邮件内容
闪闪生成密钥S
闪闪使用密钥S,将邮件内容进行加密,得到DATA
闪闪使用公钥,将密钥S进行加密,得到KEY
闪闪推送$KEY,$DATA到客户的$PushURL
客户使用$PushKey,将得到$KEY进行解密,得到密钥S
客户使用密钥S,将得到的$DATA进行解密,得到原始邮件内容

参数说明
| 参数 | 分类 | 类型 | 必须 | 说明 |
|---|---|---|---|---|
| Authorization | header | string | 是 | $KEY |
| Content-Type | header | string | 是 | text/plain |
| data | body | text | 是 | 加密的邮件内容,见示例 |
示例
xxxxxxxxxxcurl -X POST $PushURL \-H "Authorization: $KEY" \-H "Content-Type: text/plain" \--data $DATA
xxxxxxxxxx邮件内容加密前的原始格式:{"userId": "00240","id": "ss_1634037878869","name": "会员30天唤醒邮件1号模板","subject": "亲亲亲们快来看我们双十一的大优惠","summary": "","content": "<html lang=\"en\"></html>","snapshot": "https://shanedit.ifaxin.com/editor/29/20211014/6fa63fbac71628fd3f70322e59f64ed1.png","extra": {"user_tag": "母婴、化妆品","user_location": "wuhan"},"createTime": "2021-10-14 14:40:15","updateTime": "2021-10-14 16:24:36","timestamp": 1634199876966}
返回值示例
xxxxxxxxxx客户成功接收并处理,需要返回1、HTTP 状态码 2002、返回字符串 "OK"闪闪接口给 $PushURL 的推送不做失败重试。
xxxxxxxxxx# coding: utf-8import requestsimport jsonimport base64import datetimefrom Crypto.PublicKey import RSAfrom Crypto.Cipher import PKCS1_v1_5, AESAPP_ID = ''APP_KEY = ''HOST = 'www.shanedit.com'class Shanshan:def __init__(self, user_info):self.user_info = user_infoself.token = Noneself.expire_time = Nonedef _valid_token(self):if not self.expire_time:self.auth()now = datetime.datetime.now()if now > self.expire_time - datetime.timedelta(hours=1):self.auth()def auth(self):url = f"https://{HOST}/access/token"auth = str(base64.b64encode((APP_ID + ':' + APP_KEY).encode('utf8')), 'utf8')headers = {'Content-Type': 'application/json','Authorization': auth}response = requests.request("POST", url, headers=headers, data=json.dumps(self.user_info))self.token = response.json()['data']['token']self.expire_time = datetime.datetime.strptime(response.json()['data']['expireTime'], '%Y-%m-%d %H:%M:%S')return self.tokendef code(self):self._valid_token()url = f"https://{HOST}/access/code"auth = f'Bearer {self.token}'headers = {'Content-Type': 'application/json','Authorization': auth}response = requests.request("POST", url, headers=headers)return response.json()['data']def create(self, email_info):self._valid_token()url = f"https://{HOST}/access/email"auth = f'Bearer {self.token}'headers = {'Content-Type': 'application/json','Authorization': auth}response = requests.request("POST", url, headers=headers, data=json.dumps(email_info))return response.json()['data']['id']def copy(self, email_info):self._valid_token()url = f"https://{HOST}/access/email/copy"auth = f'Bearer {self.token}'headers = {'Content-Type': 'application/json','Authorization': auth}response = requests.request("POST", url, headers=headers, data=json.dumps(email_info))return response.json()['data']['id']def decrypt_key(self, KEY):DEFAULT = 128KEY = base64.b64decode(bytes(KEY, 'utf-8'))length = len(KEY)rsa_private_key = RSA.importKey(open('./push_key.pem', 'r').read().strip('\n'))cipher = PKCS1_v1_5.new(rsa_private_key)if length < DEFAULT:decrypt_byte = cipher.decrypt(KEY, 'failure')else:offset = 0res = []while length - offset > 0:if length - offset > DEFAULT:res.append(cipher.decrypt(KEY[offset: offset + DEFAULT], 'failure'))else:res.append(cipher.decrypt(KEY[offset:], 'failure'))offset += DEFAULTdecrypt_byte = b''.join(res)decrypted = decrypt_byte.decode()return decrypteddef decrypt_data(self, key, data):unpad = lambda s: s[:-ord(s[len(s) - 1:])]enc = base64.b64decode(data)cipher = AES.new(bytes(key, 'utf-8'), AES.MODE_ECB)content_b = unpad(cipher.decrypt(enc))return str(content_b, 'utf-8')def main():user_info = {"id": 244,"name": "liubida2","email": "liubida2@sendcloud.im","phone": 13488889999}ss = Shanshan(user_info)email_info = {"name": "会员30天唤醒邮件2号模板","extra": {"location": "wuhan"}}token = ss.auth()print(f'获取token:{token}')print('----')code = ss.code()email_id = ss.create(email_info)print(f'临时code:{code}')print(f'创建邮件:https://www.shanedit.com/thirdApp?code={code}&id={email_id}')print('----')code = ss.code()print(f'临时code:{code}')print(f'编辑邮件:https://www.shanedit.com/thirdApp?code={code}&id={email_id}')print('----')code = ss.code()copy_email_id = ss.copy({'id':email_id})print(f'临时code:{code}')print(f'copy邮件:https://www.shanedit.com/thirdApp?code={code}&id={copy_email_id}')# 假定收到如下的KEY、DATAKEY = ''DATA = ''pri_key = ss.decrypt_key(KEY)email = ss.decrypt_data(pri_key, DATA)if __name__ == '__main__':main()
详见:Example.zip