├── .gitignore ├── src ├── Core │ ├── Exceptions │ │ ├── ApiException.php │ │ ├── GetAccessTokenException.php │ │ ├── MissingSecretException.php │ │ ├── InvalidArgumentException.php │ │ └── QQExmailException.php │ ├── MessageFormatter.php │ ├── AccessToken.php │ ├── Middleware │ │ └── CheckApiResponseMiddleware.php │ └── BaseApi.php ├── Contact │ ├── BaseContactApi.php │ ├── Group.php │ ├── Department.php │ └── User.php ├── UniqueLogin │ └── UniqueLogin.php ├── MailNotice │ └── Mail.php ├── FunctionSetting │ └── UserOption.php ├── SystemLog │ └── Log.php └── QQExmail.php ├── composer.json ├── LICENSE └── README.md /.gitignore: -------------------------------------------------------------------------------- 1 | /vendor/ 2 | composer.lock 3 | .idea 4 | -------------------------------------------------------------------------------- /src/Core/Exceptions/ApiException.php: -------------------------------------------------------------------------------- 1 | apiGet(self::API_GET_LOGIN_URL, ['userid' => $userId])); 20 | } 21 | 22 | protected function getAppName() 23 | { 24 | return 'unique_login'; 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /src/MailNotice/Mail.php: -------------------------------------------------------------------------------- 1 | $userId, 21 | 'begin_date' => $this->formatDate($begin), 22 | 'end_date' => $this->formatDate($end), 23 | ]; 24 | 25 | return self::parseJson($this->apiGet(self::API_NET_ACCOUNT, $req)); 26 | } 27 | 28 | // todo 回调模式 29 | 30 | protected function getAppName() 31 | { 32 | return 'mail_notice'; 33 | } 34 | } 35 | -------------------------------------------------------------------------------- /src/FunctionSetting/UserOption.php: -------------------------------------------------------------------------------- 1 | apiJson(self::API_GET, ['userid' => $userId, 'type' => $types])); 26 | } 27 | 28 | public function update($userId, array $options) 29 | { 30 | return static::parseJson($this->apiJson(self::API_UPDATE, ['userid' => $userId, 'option' => $options])); 31 | } 32 | 33 | protected function getAppName() 34 | { 35 | return 'function_setting'; 36 | } 37 | } 38 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2017 leo 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /src/Contact/Group.php: -------------------------------------------------------------------------------- 1 | apiGet(self::API_GET, ['groupid' => $groupId])); 26 | } 27 | 28 | public function create($groupId, $data) 29 | { 30 | return static::parseJson($this->apiJson(self::API_CREATE, array_merge($data, ['groupid' => $groupId]))); 31 | } 32 | 33 | public function update($groupId, $data) 34 | { 35 | return static::parseJson($this->apiJson(self::API_UPDATE, array_merge($data, ['groupid' => $groupId]))); 36 | } 37 | 38 | public function delete($groupId) 39 | { 40 | return static::parseJson($this->apiGet(self::API_DELETE, ['groupid' => $groupId])); 41 | } 42 | } 43 | -------------------------------------------------------------------------------- /src/Contact/Department.php: -------------------------------------------------------------------------------- 1 | apiJson(self::API_CREATE, $data)); 22 | } 23 | 24 | public function update($id, $data) 25 | { 26 | return static::parseJson($this->apiJson(self::API_UPDATE, array_merge($data, ['id' => $id]))); 27 | } 28 | 29 | public function delete($id) 30 | { 31 | return static::parseJson($this->apiGet(self::API_DELETE, ['id' => $id])); 32 | } 33 | 34 | public function departmentList($id = null) 35 | { 36 | $query = []; 37 | if (!is_null($id)) { 38 | $query['id'] = $id; 39 | } 40 | 41 | return static::parseJson($this->apiGet(self::API_LIST, $query)); 42 | } 43 | 44 | public function search($name, $fuzzy = false) 45 | { 46 | return static::parseJson($this->apiJson(self::API_SEARCH, [ 47 | 'name' => $name, 48 | 'fuzzy' => $fuzzy ? 1 : 0, 49 | ])); 50 | } 51 | } 52 | -------------------------------------------------------------------------------- /src/Core/MessageFormatter.php: -------------------------------------------------------------------------------- 1 | hideAccessToken = $hideAccessToken; 26 | } 27 | 28 | /** 29 | * @return bool 30 | */ 31 | public function isHideAccessToken() 32 | { 33 | return $this->hideAccessToken; 34 | } 35 | 36 | /** 37 | * @param bool $hideAccessToken 38 | */ 39 | public function setHideAccessToken($hideAccessToken) 40 | { 41 | $this->hideAccessToken = $hideAccessToken; 42 | } 43 | 44 | public function format( 45 | RequestInterface $request, 46 | ResponseInterface $response = null, 47 | \Exception $error = null 48 | ) { 49 | if ($this->isHideAccessToken()) { 50 | $query = \GuzzleHttp\Psr7\parse_query($request->getUri()->getQuery()); 51 | $query['access_token'] = 'hidden'; 52 | $uri = $request->getUri()->withQuery(http_build_query($query)); 53 | $request = $request->withUri($uri); 54 | } 55 | 56 | return parent::format($request, $response, $error); 57 | } 58 | } 59 | -------------------------------------------------------------------------------- /src/Core/AccessToken.php: -------------------------------------------------------------------------------- 1 | getCacheKey($app); 20 | $cache = $this->getSDK()->getCache(); 21 | if ($refresh || !$ret = $cache->get($cacheKey)) { 22 | $token = $this->getTokenFromServer($app); 23 | $cache->set($cacheKey, $token['access_token'], $token['expires_in'] - 1500); 24 | 25 | return $token['access_token']; 26 | } 27 | 28 | return $ret; 29 | } 30 | 31 | public function getTokenFromServer($app) 32 | { 33 | $ret = static::parseJson($this->apiGet(self::API_GET_TOKEN, [ 34 | 'corpid' => $this->getSDK()->getCorpId(), 35 | 'corpsecret' => $this->getSDK()->getCorpSecret($app), 36 | ])); 37 | if (empty($ret['access_token'])) { 38 | throw new GetAccessTokenException('get AccessToken fail. response: '.json_encode($ret)); 39 | } 40 | 41 | return $ret; 42 | } 43 | 44 | public function getCacheKey($app) 45 | { 46 | $prefix = $this->getSDK()->getCacheKeyPrefix(); 47 | $corpId = $this->getSDK()->getCorpId(); 48 | 49 | return sprintf('%s.access_token.%s.%s', $prefix, $corpId, $app); 50 | } 51 | 52 | protected function getAppName() 53 | { 54 | // disable token middleware 55 | return null; 56 | } 57 | } 58 | -------------------------------------------------------------------------------- /src/Contact/User.php: -------------------------------------------------------------------------------- 1 | apiGet(self::API_GET, ['userid' => $userId])); 28 | } 29 | 30 | public function create($data) 31 | { 32 | return static::parseJson($this->apiJson(self::API_CREATE, $data)); 33 | } 34 | 35 | public function update($userId, $data) 36 | { 37 | return static::parseJson($this->apiJson(self::API_UPDATE, array_merge($data, ['userid' => $userId]))); 38 | } 39 | 40 | public function delete($userId) 41 | { 42 | return static::parseJson($this->apiGet(self::API_DELETE, ['userid' => $userId])); 43 | } 44 | 45 | public function simpleList($departmentId, $fetchChild = false) 46 | { 47 | return static::parseJson($this->apiGet(self::API_SIMPLE_LIST, [ 48 | 'department_id' => $departmentId, 49 | 'fetch_child' => $fetchChild ? 1 : 0, 50 | ])); 51 | } 52 | 53 | public function userList($departmentId, $fetchChild = false) 54 | { 55 | return static::parseJson($this->apiGet(self::API_LIST, [ 56 | 'department_id' => $departmentId, 57 | 'fetch_child' => $fetchChild ? 1 : 0, 58 | ])); 59 | } 60 | 61 | public function batchCheck(array $userIdArr) 62 | { 63 | return static::parseJson($this->apiJson(self::API_BATCH_CHECK, ['userlist' => $userIdArr])); 64 | } 65 | } 66 | -------------------------------------------------------------------------------- /src/Core/Middleware/CheckApiResponseMiddleware.php: -------------------------------------------------------------------------------- 1 | shouldCheck = $shouldCheck; 36 | $this->responseParser = $responseParser; 37 | } 38 | 39 | public function __invoke() 40 | { 41 | return function (callable $handler) { 42 | return function (RequestInterface $request, array $options) use ($handler) { 43 | if (is_bool($this->shouldCheck)) { 44 | $shouldCheck = $this->shouldCheck; 45 | } else { 46 | $shouldCheck = call_user_func($this->shouldCheck, $request); 47 | } 48 | if (!$shouldCheck) { 49 | return $handler($request, $options); 50 | } 51 | 52 | return $handler($request, $options)->then( 53 | function (ResponseInterface $response) { 54 | $ret = call_user_func($this->responseParser, $response); 55 | if (!$ret) { 56 | throw new ApiException('decode failed, response:'.$response->getBody()); 57 | } 58 | if ($ret['errcode'] != 0) { 59 | throw new ApiException($ret['errmsg'], $ret['errcode']); 60 | } 61 | 62 | return $response; 63 | }, 64 | function ($reason) { 65 | throw new ApiException($reason); 66 | } 67 | ); 68 | }; 69 | }; 70 | } 71 | } 72 | -------------------------------------------------------------------------------- /src/SystemLog/Log.php: -------------------------------------------------------------------------------- 1 | $domain, 'begin_date' => $this->formatDate($begin), 'end_date' => $this->formatDate($end)]; 33 | 34 | return self::parseJson($this->apiJson(self::API_MAIL_STATUS, $req)); 35 | } 36 | 37 | public function mail($mailType, $begin, $end, $filters = []) 38 | { 39 | $req = [ 40 | 'mailtype' => $mailType, 41 | 'begin_date' => $this->formatDate($begin), 42 | 'end_date' => $this->formatDate($end), 43 | ]; 44 | if (isset($filters['userid'])) { 45 | $req['userid'] = $filters['userid']; 46 | } 47 | if (isset($filters['subject'])) { 48 | $req['subject'] = $filters['subject']; 49 | } 50 | 51 | return self::parseJson($this->apiJson(self::API_MAIL, $req)); 52 | } 53 | 54 | public function login($userId, $begin, $end) 55 | { 56 | $req = [ 57 | 'userid' => $userId, 58 | 'begin_date' => $this->formatDate($begin), 59 | 'end_date' => $this->formatDate($end), 60 | ]; 61 | 62 | return self::parseJson($this->apiJson(self::API_LOGIN, $req)); 63 | } 64 | 65 | public function batchJob($begin, $end) 66 | { 67 | $req = [ 68 | 'begin_date' => $this->formatDate($begin), 69 | 'end_date' => $this->formatDate($end), 70 | ]; 71 | 72 | return self::parseJson($this->apiJson(self::API_BATCH_JOB, $req)); 73 | } 74 | 75 | public function operation($type, $begin, $end) 76 | { 77 | $req = [ 78 | 'type' => $type, 79 | 'begin_date' => $this->formatDate($begin), 80 | 'end_date' => $this->formatDate($end), 81 | ]; 82 | 83 | return self::parseJson($this->apiJson(self::API_OPERATION, $req)); 84 | } 85 | 86 | protected function getAppName() 87 | { 88 | return 'system_log'; 89 | } 90 | } 91 | -------------------------------------------------------------------------------- /src/QQExmail.php: -------------------------------------------------------------------------------- 1 | cache = $cache ?: new ArrayCachePool(); 76 | $this->parseConfig($config); 77 | } 78 | 79 | /** 80 | * @return CacheInterface 81 | */ 82 | public function getCache() 83 | { 84 | return $this->cache; 85 | } 86 | 87 | /** 88 | * @param CacheInterface $cache 89 | */ 90 | public function setCache($cache) 91 | { 92 | $this->cache = $cache; 93 | } 94 | 95 | /** 96 | * @return string 97 | */ 98 | public function getCorpId() 99 | { 100 | return $this->corpId; 101 | } 102 | 103 | /** 104 | * @param string $app 105 | * @throws MissingSecretException 106 | * @return string 107 | */ 108 | public function getCorpSecret($app) 109 | { 110 | if (!isset($this->corpSecrets[$app])) { 111 | throw new MissingSecretException('缺少 secret: '.$app); 112 | } 113 | 114 | return $this->corpSecrets[$app]; 115 | } 116 | 117 | /** 118 | * @return string 119 | */ 120 | public function getCacheKeyPrefix() 121 | { 122 | return $this->cacheKeyPrefix; 123 | } 124 | 125 | protected function getApiMap() 126 | { 127 | return [ 128 | 'accessToken' => AccessToken::class, 129 | 'user' => User::class, 130 | 'department' => Department::class, 131 | 'group' => Group::class, 132 | 'userOption' => UserOption::class, 133 | 'uniqueLogin' => UniqueLogin::class, 134 | 'log' => Log::class, 135 | 'mail' => Mail::class, 136 | ]; 137 | } 138 | 139 | protected function parseConfig(array $config) 140 | { 141 | if (!isset($config['corp_id'])) { 142 | throw new InvalidArgumentException('缺少 corp_id 参数'); 143 | } 144 | 145 | $this->corpId = $config['corp_id']; 146 | 147 | if (!isset($config['corp_secrets']) || empty($config['corp_secrets'])) { 148 | throw new InvalidArgumentException('缺少 corp_secrets 参数'); 149 | } 150 | 151 | $this->corpSecrets = $config['corp_secrets']; 152 | 153 | if (isset($config['cache_key_prefix'])) { 154 | $this->cacheKeyPrefix = $config['cache_key_prefix']; 155 | } 156 | 157 | $this->config = $config; 158 | } 159 | } 160 | -------------------------------------------------------------------------------- /src/Core/BaseApi.php: -------------------------------------------------------------------------------- 1 | sdk; 33 | } 34 | 35 | protected function getFullApiUrl($api) 36 | { 37 | return 'https://api.exmail.qq.com/cgi-bin/'.ltrim($api, '/'); 38 | } 39 | 40 | /** 41 | * @param ResponseInterface $response 42 | * @return array|null 43 | */ 44 | public static function parseJson(ResponseInterface $response) 45 | { 46 | return \GuzzleHttp\json_decode($response->getBody(), true, 512, JSON_BIGINT_AS_STRING); 47 | } 48 | 49 | /** 50 | * @return array 51 | */ 52 | protected function getHttpMiddleware() 53 | { 54 | return array_filter([ 55 | $this->getCheckApiResponseMiddleware(), 56 | $this->getRetryMiddleware(), 57 | $this->getTokenMiddleware(), 58 | $this->getLogRequestMiddleware(), 59 | ]); 60 | } 61 | 62 | /** 63 | * @return CheckApiResponseMiddleware 64 | */ 65 | protected function getCheckApiResponseMiddleware() 66 | { 67 | return new CheckApiResponseMiddleware(true, [static::class, 'parseJson']); 68 | } 69 | 70 | /** 71 | * @return callable 72 | */ 73 | protected function getLogRequestMiddleware() 74 | { 75 | $logger = $this->getSDK()->getLogger(); 76 | $hideToken = $this->getSDK()->getConfig('log.hide_access_token', true); 77 | $formatter = new MessageFormatter($this->getSDK()->getConfig('log.format', MessageFormatter::CLF), $hideToken); 78 | $logLevel = $this->getSDK()->getConfig('log.level', LogLevel::INFO); 79 | 80 | return Middleware::log($logger, $formatter, $logLevel); 81 | } 82 | 83 | /** 84 | * @return TokenMiddleware 85 | */ 86 | protected function getTokenMiddleware() 87 | { 88 | $app = $this->getAppName(); 89 | if (is_null($app)) { 90 | return null; 91 | } 92 | 93 | return new TokenMiddleware(true, function (RequestInterface $request) use ($app) { 94 | return $this->attachAccessToken($app, $request); 95 | }); 96 | } 97 | 98 | /** 99 | * @return callable 100 | */ 101 | protected function getRetryMiddleware() 102 | { 103 | return Middleware::retry(function ($retries, RequestInterface $request, ResponseInterface $response = null) { 104 | if ($retries >= $this->getSDK()->getConfig('api_retry', 3)) { 105 | return false; 106 | } 107 | if (!$response || $response->getStatusCode() >= 400) { 108 | return true; 109 | } 110 | 111 | $ret = static::parseJson($response); 112 | if (in_array($ret['errcode'], ['40001', '40014'])) { 113 | // 刷新 access token 114 | $this->getSDK()->accessToken->getToken(true); 115 | 116 | return true; 117 | } 118 | 119 | return false; 120 | }); 121 | } 122 | 123 | /** 124 | * 在请求的 url 后加上 access_token 参数 125 | * 126 | * @param string $app 127 | * @param RequestInterface $request 128 | * @param bool $cache 129 | * 130 | * @return RequestInterface 131 | */ 132 | private function attachAccessToken($app, RequestInterface $request, $cache = true) 133 | { 134 | $query = \GuzzleHttp\Psr7\parse_query($request->getUri()->getQuery()); 135 | $query['access_token'] = $this->getSDK()->accessToken->getToken($app, !$cache); 136 | $uri = $request->getUri()->withQuery(http_build_query($query)); 137 | 138 | return $request->withUri($uri); 139 | } 140 | 141 | /** 142 | * @param string|\DateTime $date 143 | * @return string 144 | */ 145 | protected function formatDate($date) 146 | { 147 | if ($date instanceof \DateTime) { 148 | return $date->format('Y-m-d'); 149 | } 150 | 151 | return $date; 152 | } 153 | 154 | abstract protected function getAppName(); 155 | } 156 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # qq-exmail 2 | 新版 QQ 企业邮箱接口 SDK,接口文档 https://exmail.qq.com/qy_mng_logic/doc#10001 3 | 4 | ## 安装 5 | 6 | `composer require leo108/qq-exmail -vvv` 7 | 8 | ## 快速开始 9 | 10 | ``` 11 | $config = [ 12 | 'corp_id' => 'CORP_ID', 13 | 'corp_secrets' => [ 14 | 'contact' => '通讯录管理 Secret', 15 | 'unique_login' => '单点登录 Secret', 16 | 'mail_notice' => '新邮件提醒 Secret', 17 | 'function_setting' => '功能设置 Secret', 18 | 'system_log' => '日志查询 Secret' 19 | ], 20 | 'log' => [ 21 | 'format' => '{method} {url} {code} {res_header_Content-Length}', 22 | 'hide_access_token' => true, 23 | ], 24 | ]; 25 | $exmail = new Leo108\QQExmail\QQExmail($config); 26 | 27 | // 创建一个新用户, 更多参数请参考 API 文档 28 | $exmail->user->create([ 29 | 'userid' => 'leo108@exmail.com', 30 | 'name' => 'leo108', 31 | 'department' => [1], 32 | 'password' => 'secret', 33 | 'gender' => Leo108\QQExmail\Contact\User::GENDER_MALE, // 如果你不想踩坑,还是乖乖用我提供的常量吧 :) 34 | ]); 35 | ``` 36 | 37 | ## 构造函数 38 | 39 | ``` 40 | public function __construct( 41 | array $config = [], 42 | Psr\SimpleCache\CacheInterface $cache = null, 43 | GuzzleHttp\ClientInterface $httpClient = null, 44 | Psr\Log\LoggerInterface $logger = null 45 | ) 46 | ``` 47 | 48 | * 第一个参数为[配置项](#配置项)。 49 | * 第二个参数是一个符合 PSR-16 规范的缓存对象,用于保存各个应用的 access token,如果不传则默认使用内存缓存,即每次生命周期的各个应用第一次请求都会先通过 api 获得对应的 access token。Laravel 项目可以使用这个类 [SimpleCacheBridge.php](https://gist.github.com/leo108/bd7559654c52000cc9774a80b072c629) 50 | * 第三个参数是一个 [GuzzleHttp](https://github.com/guzzle/guzzle) 对象,没有特殊需求可以保持 `null`。 51 | * 第四个参数是一个符合 PSR-3 规范的日志对象,用于打印日志,如果留空则不答应任何日志。 52 | 53 | ## 配置项 54 | 55 | * `corp_id` 可以在企业邮箱的"工具箱"->"应用中心"页面最下方找到。 56 | * `corp_secrets` 从"应用中心"页面进入各个应用,可以找到对应的 secret。对于用不到的应用,可以不配置对应的 secret。 57 | * `log.format` 定义日志格式,各个字段可以参考 https://github.com/guzzle/guzzle/blob/master/src/MessageFormatter.php 58 | * `log.hide_access_token` 如果设定为 `true` 则会隐藏日志中 access token 的值,避免 token 泄露。 59 | 60 | ## 异常 61 | 62 | 本项目中所有的异常均继承自 `Leo108\QQExmail\Core\Exceptions\QQExmailException` 63 | 64 | * `Leo108\QQExmail\Core\Exceptions\GetAccessTokenException` 使用 corp id 和 corp secret 换取 access token 失败 65 | * `Leo108\QQExmail\Core\Exceptions\MissingSecretException` 使用应用却没有配置该应用的 secret 66 | * `Leo108\QQExmail\Core\Exceptions\InvalidArgumentException` 初始化时传入的配置有误 67 | * `Leo108\QQExmail\Core\Exceptions\ApiException` 当 API 接口返回的 errcode 字段不为 0 时抛出 68 | 69 | ## API 列表 70 | 71 | * [部门管理](#部门管理) 72 | * [成员管理](#成员管理) 73 | * [邮件群组管理](#邮件群组管理) 74 | * [功能设置](#功能设置) 75 | * [系统日志](#系统日志) 76 | * [新邮件提醒](#新邮件提醒) 77 | * [单点登录](#单点登录) 78 | 79 | ### 部门管理 80 | 81 | 创建部门 https://exmail.qq.com/qy_mng_logic/doc#10008 82 | 83 | ``` 84 | $exmail->department->create([ 85 | 'name' => '技术部', 86 | 'parentid' => 1, 87 | ]); 88 | ``` 89 | 90 | 更新部门 https://exmail.qq.com/qy_mng_logic/doc#10009 91 | 92 | ``` 93 | $exmail->department->update($departmentId, [ 94 | 'name' => '技术部', 95 | 'parentid' => 1, 96 | 'order' => 100 97 | ]); 98 | ``` 99 | 100 | 删除部门 https://exmail.qq.com/qy_mng_logic/doc#10010 101 | 102 | ``` 103 | $exmail->department->delete($departmentId); 104 | ``` 105 | 106 | 获取部门列表 https://exmail.qq.com/qy_mng_logic/doc#10011 107 | 108 | ``` 109 | // 获取全部部门 110 | $exmail->department->departmentList(); 111 | 112 | // 获取 $departmentId 部门及其子部门 113 | $exmail->department->departmentList($departmentId); 114 | ``` 115 | 116 | 查找部门 https://exmail.qq.com/qy_mng_logic/doc#10012 117 | 118 | ``` 119 | $exmail->department->search('关键词', true); // 第二个参数为 true 时则为模糊搜索 120 | ``` 121 | 122 | ### 成员管理 123 | 124 | 创建成员 https://exmail.qq.com/qy_mng_logic/doc#10014 125 | 126 | ``` 127 | $exmail->user->create([ 128 | 'userid' => 'leo108@exmail.com', 129 | 'name' => 'leo108', 130 | 'department' => [1], 131 | 'password' => 'secret', 132 | 'gender' => Leo108\QQExmail\Contact\User::GENDER_MALE, 133 | ]); 134 | ``` 135 | 136 | 更新成员 https://exmail.qq.com/qy_mng_logic/doc#10015 137 | 138 | ``` 139 | $exmail->user->update('leo108@exmail.com', [ 140 | 'name' => 'Leo Chen', 141 | ]); 142 | ``` 143 | 144 | 删除成员 https://exmail.qq.com/qy_mng_logic/doc#10016 145 | 146 | ``` 147 | $exmail->user->delete('leo108@exmail.com'); 148 | ``` 149 | 150 | 获取成员 https://exmail.qq.com/qy_mng_logic/doc#10017 151 | 152 | ``` 153 | $exmail->user->get('leo108@exmail.com'); 154 | ``` 155 | 156 | 获取部门成员 https://exmail.qq.com/qy_mng_logic/doc#10018 157 | 158 | ``` 159 | $exmail->user->simpleList($departmentId, true); // 第二个参数为 true 时递归获取子部门成员 160 | ``` 161 | 162 | 获取部门成员(详情) https://exmail.qq.com/qy_mng_logic/doc#10019 163 | 164 | ``` 165 | $exmail->user->userList($departmentId, true); // 第二个参数为 true 时递归获取子部门成员 166 | ``` 167 | 168 | 批量检查帐号 https://exmail.qq.com/qy_mng_logic/doc#10020 169 | 170 | ``` 171 | $exmail->user->batchCheck(['leo108@exmail.com', 'test@exmail.com']); 172 | ``` 173 | 174 | ### 邮件群组管理 175 | 176 | 创建邮件群组 https://exmail.qq.com/qy_mng_logic/doc#10022 177 | 178 | ``` 179 | $exmail->group->create([ 180 | 'groupid' => 'group_name@exmail.com', 181 | 'groupname' => '测试邮件群组', 182 | 'userlist' => ['leo108@exmail.com', 'test@exmail.com'], 183 | 'allow_type' => Leo108\QQExmail\Contact\Group::ALLOW_TYPE_ALL, 184 | ]); 185 | ``` 186 | 187 | 更新邮件群组 https://exmail.qq.com/qy_mng_logic/doc#10023 188 | 189 | ``` 190 | $exmail->group->update('group_name@exmail.com', [ 191 | 'groupname' => '技术部邮件组', 192 | ]); 193 | ``` 194 | 195 | 删除邮件群组 https://exmail.qq.com/qy_mng_logic/doc#10024 196 | 197 | ``` 198 | $exmail->group->delete('group_name@exmail.com'); 199 | ``` 200 | 201 | 获取邮件群组信息 https://exmail.qq.com/qy_mng_logic/doc#10025 202 | 203 | ``` 204 | $exmail->group->get('group_name@exmail.com'); 205 | ``` 206 | 207 | ### 功能设置 208 | 209 | 获取功能属性 https://exmail.qq.com/qy_mng_logic/doc#10047 210 | 211 | ``` 212 | $exmail->userOption->get('leo108@exmail.com', [ 213 | Leo108\QQExmail\FunctionSetting\UserOption::TYPE_FORCE_SSL, 214 | Leo108\QQExmail\FunctionSetting\UserOption::TYPE_IMAP_SMTP, 215 | Leo108\QQExmail\FunctionSetting\UserOption::TYPE_POP_SMTP, 216 | Leo108\QQExmail\FunctionSetting\UserOption::TYPE_ENABLE_SSL, 217 | ]); 218 | ``` 219 | 220 | 更改功能属性 https://exmail.qq.com/qy_mng_logic/doc#10048 221 | 222 | ``` 223 | $exmail->userOption->update('leo108@exmail.com', [ 224 | ['type' => Leo108\QQExmail\FunctionSetting\UserOption::TYPE_FORCE_SSL, 'value' => '1'], 225 | ['type' => Leo108\QQExmail\FunctionSetting\UserOption::TYPE_IMAP_SMTP, 'value' => '1'], 226 | ['type' => Leo108\QQExmail\FunctionSetting\UserOption::TYPE_POP_SMTP, 'value' => '1'], 227 | ['type' => Leo108\QQExmail\FunctionSetting\UserOption::TYPE_ENABLE_SSL, 'value' => '1'], 228 | ]); 229 | ``` 230 | 231 | ### 系统日志 232 | 233 | 查询邮件概况 https://exmail.qq.com/qy_mng_logic/doc#10027 234 | 235 | ``` 236 | $exmail->log->mailStatus('exmail.com', '2016-10-01', '2016-10-07'); 237 | ``` 238 | 239 | 查询邮件 https://exmail.qq.com/qy_mng_logic/doc#10028 240 | 241 | ``` 242 | $exmail->log->mail(Leo108\QQExmail\SystemLog\Log::MAIL_TYPE_RECEIVE_AND_SEND, '2016-10-01', '2016-10-07', [ 243 | 'userid' => 'leo108@exmail.com', 244 | 'subject' => '查询关键词' 245 | ]); 246 | ``` 247 | 248 | 查询成员登录 https://exmail.qq.com/qy_mng_logic/doc#10029 249 | 250 | ``` 251 | $exmail->log->login('leo108@exmail.com', '2016-10-01', '2016-10-07'); 252 | ``` 253 | 254 | 查询批量任务 https://exmail.qq.com/qy_mng_logic/doc#10030 255 | 256 | ``` 257 | $exmail->log->batchJob('2016-10-01', '2016-10-07'); 258 | ``` 259 | 260 | 查询操作记录 https://exmail.qq.com/qy_mng_logic/doc#10031 261 | 262 | ``` 263 | $exmail->log->operation(Leo108\QQExmail\SystemLog\Log::OPERATION_TYPE_ALL, '2016-10-01', '2016-10-07'); 264 | ``` 265 | 266 | ### 新邮件提醒 267 | 268 | 获取邮件未读数 https://exmail.qq.com/qy_mng_logic/doc#10033 269 | 270 | ``` 271 | $exmail->mail->newAccount('leo108@exmail.com', '2016-10-01', '2016-10-07'); 272 | ``` 273 | 274 | 获取邮件未读数(回调模式)尚未实现 275 | 276 | ### 单点登录 277 | 278 | 获取登录企业邮的url https://exmail.qq.com/qy_mng_logic/doc#10036 279 | 280 | ``` 281 | $exmail->uniqueLogin->getLoginUrl('leo108@exmail.com'); 282 | ``` 283 | 284 | ## 其他 285 | 286 | 本项目是基于我的另外一个开源项目 [php_sdk_skeleton](https://github.com/leo108/php_sdk_skeleton) 开发的。 287 | 通过 php_sdk_skeleton 可以快速构建基于 Http API 的 SDK。 288 | 289 | ## License 290 | 291 | [MIT](https://github.com/leo108/qq-exmail/blob/master/LICENSE). 292 | --------------------------------------------------------------------------------