# djangomail
[![Build Status](https://travis-ci.com/somenzz/djangomail.svg?branch=master)](https://travis-ci.com/somenzz/djangomail)
将 mail 模块从 Django 5.0 中独立出来,做为 Python 发邮件的独立的库,就是 djangomail,使用起来比 smtplib 要方便很多。
## 安装
```shell
pip install djangomail
```
### 配置
发邮件要用户名密码和邮件服务器,对吧,直接写在配置文件里。在我们的程序的目录中,新建 settings.py
写入以下信息:
```python
EMAIL_USE_LOCALTIME = True
EMAIL_USE_SSL = True
EMAIL_HOST = 'smtp.163.com' #可以换其他邮箱,注意修改确认端口
EMAIL_PORT = 465
EMAIL_HOST_USER = 'your-username'
EMAIL_HOST_PASSWORD = '********'
DEFAULT_FROM_EMAIL = EMAIL_HOST_USER
```
### 发送普通文本邮件
只需要导入 send_mail,send_mass_mail,设置下环境变量 `SETTINGS_MODULE`, 这是 Django 读取自定义配置文件的内容所需要的。
示例代码如下:
```python
from djangomail import send_mail,send_mass_mail
import settings
receivers = ['somenzz@163.com']
send_mail(
subject="如何使用 django mail",
message="djangomail 发送邮件从未如此简单,来自 「Python七号」",
from_email=settings.DEFAULT_FROM_EMAIL,
recipient_list=receivers
)
```
查看下邮箱:
![](https://tva1.sinaimg.cn/large/008i3skNgy1grd95qcxldj30sc0dsglv.jpg)
还可以一次发送不同的邮件给不同的人:
```python
datatuple = (
('Subject', 'Message.', 'from@example.com', ['john@example.com']),
('Subject', 'Message.', 'from@example.com', ['jane@example.com']),
)
send_mass_mail(datatuple)
```
### 发送带附件的邮件
发送附件需要使用 EmailMessage 类,其实常用的 send_mail,send_mass_mail 函数只对 EmailMessage 少数成员函数的封装。也就是说发送附件,我们需要创建 EmailMessage 对象。
示例代码如下:
```python
from djangomail import EmailMessage
import settings
import os
os.environ.setdefault("SETTINGS_MODULE", "settings") #此行代码也可以不写,默认的指向就是 settings.py
receivers = ['somenzz@163.com']
email = EmailMessage(
subject='如何使用 djangomail 发送附件',
body='这里有附件',
from_email=settings.DEFAULT_FROM_EMAIL,
to = receivers,
reply_to=['897665600@qq.com']
)
email.attach_file("/Users/aaron/Documents/python-seven.jpg", mimetype="image/jpeg")
email.attach_file("./settings.py")
email.send()
```
检查下邮箱:
![](https://tva1.sinaimg.cn/large/008i3skNgy1grda7uakxij30vw0i874m.jpg)
### 发送多彩的 html 邮件
html 可以显示丰富多彩的内容,这里以发送一个含图片的 html 为例。
需要用到标准库里的 email 模块,添加图片信息,示例代码如下:
```python
from djangomail import EmailMultiAlternatives
from email.mime.image import MIMEImage
import settings
import os
os.environ.setdefault("SETTINGS_MODULE", "settings")
subject = 'djangomail 发送带图片的 html 邮件'
body_html = '''
<html>
<body>
<p>「Python七号」每周分享一个小技巧 </p>
<img src="cid:qrcode.jpg" />
</body>
</html>
'''
msg = EmailMultiAlternatives(
subject,
body_html,
from_email=settings.DEFAULT_FROM_EMAIL,
to=['somenzz@163.com']
)
msg.mixed_subtype = 'related'
msg.attach_alternative(body_html, "text/html")
img_dir = 'images/'
image = 'qrcode.jpg'
file_path = os.path.join(img_dir, image)
with open(file_path, 'rb') as f:
img = MIMEImage(f.read())
img.add_header('Content-ID', '<{name}>'.format(name=image))
img.add_header('Content-Disposition', 'inline', filename=image)
msg.attach(img)
msg.send()
```
检查下邮箱,发现图片直接显示在了邮件内容中:
![](https://tva1.sinaimg.cn/large/008i3skNgy1grdb1hawpyj31d60s8dhw.jpg)
### 扩展
其实不止发送邮件,通过实现自己的 Backend,就可以将消息发送到任何平台。
django 自己的 global_settings 其实已经有以下配置:
```python
EMAIL_BACKEND = 'djangomail.backends.smtp.EmailBackend'
```
只要我们按照 EmailBackend 的格式编写自己的 Backend 就可以实现自定义的消息发送,比如说发送到微信。
然后修改 settings.py 文件,将 EMAIL_BACKEND 配置为自己的 Backend 即可。
EmailBackend 继承自类 BaseEmailBackend,假如我们编写自己的 MyBackend,只需要继承 BaseEmailBackend 实现它的 send_messages 方法即可:
```python
def send_messages(self, email_messages):
"""
Send one or more EmailMessage objects and return the number of email
messages sent.
"""
raise NotImplementedError(
"subclasses of BaseEmailBackend must override send_messages() method"
)
```
有个 [server酱](https://mp.weixin.qq.com/s/ibBaPbMg202XMEaG-zifVA) 可以发送到微信,你可以自己扩展下,我这里就不展开了。
### 报错自动发送邮件
当某个函数报错,也就是抛出异常时,如果发送异常相关的堆栈信息邮件给运维人员,则可以大大提升处理效率。
当然了,可以指定某些异常,只有抛出这类异常时才发邮件,也可以将不同的异常发给不同的人。
这里我已经做好了一个装饰器:somedecorators
##### 安装
```sh
pip install somedecorators
```
##### 使用
```python
from somedecorators import email_on_exception
import os
os.environ.setdefault("SETTINGS_MODULE", "settings")
@email_on_exception(['somenzz@163.com'])
def myfunc():
1/0
myfunc()
```
检查一下邮箱:
![](https://tva1.sinaimg.cn/large/008i3skNgy1grdbaqr7ooj31e60n43zx.jpg)
##### 监控指定的异常
```python
from somedecorators import email_on_exception
import os
os.environ.setdefault("SETTINGS_MODULE", "settings")
class Exception1(Exception):
pass
class Exception2(Exception):
pass
class Exception3(Exception):
pass
@email_on_exception(['somenzz@163.com'],traced_exceptions = Exception2)
def myfunc(args):
if args == 1:
raise Exception1
elif args == 2:
raise Exception2
else:
raise Exception3
myfunc(2)
```
上述代码只有在 raise Exception2 时才会发送邮件:
![](https://tva1.sinaimg.cn/large/008i3skNgy1grdbh8d2foj31de0l2myd.jpg)
##### 不同的异常发给不同的人
```python
@email_on_exception(['somenzz@163.com'],traced_exceptions = Exception2)
@email_on_exception(['others@163.com'],traced_exceptions = (Exception1, Exception3))
def myfunc(args):
if args == 1:
raise Exception1
elif args == 2:
raise Exception2
else:
raise Exception3
```
是不是非常方便?
##### 其他装饰器
**timeit**
耗时统计装饰器,单位是秒,保留 4 位小数
使用方法:
```python
from somedecorators import timeit
@timeit()
def test_timeit():
time.sleep(1)
#test_timeit cost 1.0026 seconds
@timeit(logger = your_logger)
def test_timeit():
time.sleep(1)
```
**retry**
重试装饰器。
当被装饰的函数调用抛出指定的异常时,函数会被重新调用。
直到达到指定的最大调用次数才重新抛出指定的异常,可以指定时间间隔,默认 5 秒后重试。
traced_exceptions 为监控的异常,可以为 None(默认)、异常类、或者一个异常类的列表或元组 tuple。
traced_exceptions 如果为 None,则监控所有的异常;如果指定了异常类,则若函数调用抛出指定的异常时,重新调用函数,直至成功返回结果。
未出现监控的异常时,如果指定定了 reraised_exception 则抛出 reraised_exception,否则抛出原来的异常。
```python
from somedecorators import retry
@retry(
times=2,
wait_seconds=1,
traced_exceptions=myException,
reraised_exception=CustomException,
)
def test_retry():
# time.sleep(1)
raise myException
test_retry()
```
### 其他实用三方库
- [dbinterface](https://github.com/somenzz/dbinterface): 数据库统一读、写、导出文件接口,适用于数据仓库等多数据库系统应用。支持 db2、mysql,postgres。
- [transferfile](https://github.com/somenzz/transferfile): 文件上传、下载接口,适用于文件分发系统。支持 ftp、sftp、scp、rsync。
### 联系我
公众号「Python七号」
微信号「somenzz-enjoy」
Raw data
{
"_id": null,
"home_page": "https://github.com/somenzz/djangomail",
"name": "djangomail",
"maintainer": "",
"docs_url": null,
"requires_python": "",
"maintainer_email": "",
"keywords": "python send email",
"author": "somenzz",
"author_email": "somenzz@163.com",
"download_url": "https://files.pythonhosted.org/packages/27/34/84452127cf32b20175e44d2f1599b187f7270089142399d1087ca90dc30b/djangomail-0.8.tar.gz",
"platform": null,
"description": "\n# djangomail\n\n[![Build Status](https://travis-ci.com/somenzz/djangomail.svg?branch=master)](https://travis-ci.com/somenzz/djangomail)\n\n\u5c06 mail \u6a21\u5757\u4ece Django 5.0 \u4e2d\u72ec\u7acb\u51fa\u6765\uff0c\u505a\u4e3a Python \u53d1\u90ae\u4ef6\u7684\u72ec\u7acb\u7684\u5e93\uff0c\u5c31\u662f djangomail\uff0c\u4f7f\u7528\u8d77\u6765\u6bd4 smtplib \u8981\u65b9\u4fbf\u5f88\u591a\u3002\n\n\n## \u5b89\u88c5\n\n```shell\npip install djangomail\n```\n\n\n### \u914d\u7f6e\n\n\u53d1\u90ae\u4ef6\u8981\u7528\u6237\u540d\u5bc6\u7801\u548c\u90ae\u4ef6\u670d\u52a1\u5668\uff0c\u5bf9\u5427\uff0c\u76f4\u63a5\u5199\u5728\u914d\u7f6e\u6587\u4ef6\u91cc\u3002\u5728\u6211\u4eec\u7684\u7a0b\u5e8f\u7684\u76ee\u5f55\u4e2d\uff0c\u65b0\u5efa settings.py \n\n\u5199\u5165\u4ee5\u4e0b\u4fe1\u606f\uff1a\n\n```python\nEMAIL_USE_LOCALTIME = True\nEMAIL_USE_SSL = True\nEMAIL_HOST = 'smtp.163.com' #\u53ef\u4ee5\u6362\u5176\u4ed6\u90ae\u7bb1\uff0c\u6ce8\u610f\u4fee\u6539\u786e\u8ba4\u7aef\u53e3\nEMAIL_PORT = 465\nEMAIL_HOST_USER = 'your-username'\nEMAIL_HOST_PASSWORD = '********'\nDEFAULT_FROM_EMAIL = EMAIL_HOST_USER\n```\n\n### \u53d1\u9001\u666e\u901a\u6587\u672c\u90ae\u4ef6\n\n\u53ea\u9700\u8981\u5bfc\u5165 send_mail,send_mass_mail\uff0c\u8bbe\u7f6e\u4e0b\u73af\u5883\u53d8\u91cf `SETTINGS_MODULE`\uff0c \u8fd9\u662f Django \u8bfb\u53d6\u81ea\u5b9a\u4e49\u914d\u7f6e\u6587\u4ef6\u7684\u5185\u5bb9\u6240\u9700\u8981\u7684\u3002\n\n\u793a\u4f8b\u4ee3\u7801\u5982\u4e0b\uff1a\n\n```python\nfrom djangomail import send_mail,send_mass_mail\nimport settings\n\nreceivers = ['somenzz@163.com']\n\nsend_mail(\n subject=\"\u5982\u4f55\u4f7f\u7528 django mail\",\n message=\"djangomail \u53d1\u9001\u90ae\u4ef6\u4ece\u672a\u5982\u6b64\u7b80\u5355\uff0c\u6765\u81ea \u300cPython\u4e03\u53f7\u300d\",\n from_email=settings.DEFAULT_FROM_EMAIL,\n recipient_list=receivers\n)\n```\n\n\u67e5\u770b\u4e0b\u90ae\u7bb1\uff1a\n\n![](https://tva1.sinaimg.cn/large/008i3skNgy1grd95qcxldj30sc0dsglv.jpg)\n\n\n\u8fd8\u53ef\u4ee5\u4e00\u6b21\u53d1\u9001\u4e0d\u540c\u7684\u90ae\u4ef6\u7ed9\u4e0d\u540c\u7684\u4eba\uff1a\n\n```python\ndatatuple = (\n ('Subject', 'Message.', 'from@example.com', ['john@example.com']),\n ('Subject', 'Message.', 'from@example.com', ['jane@example.com']),\n)\nsend_mass_mail(datatuple)\n```\n\n\n### \u53d1\u9001\u5e26\u9644\u4ef6\u7684\u90ae\u4ef6\n\n\u53d1\u9001\u9644\u4ef6\u9700\u8981\u4f7f\u7528 EmailMessage \u7c7b\uff0c\u5176\u5b9e\u5e38\u7528\u7684 send_mail,send_mass_mail \u51fd\u6570\u53ea\u5bf9 EmailMessage \u5c11\u6570\u6210\u5458\u51fd\u6570\u7684\u5c01\u88c5\u3002\u4e5f\u5c31\u662f\u8bf4\u53d1\u9001\u9644\u4ef6\uff0c\u6211\u4eec\u9700\u8981\u521b\u5efa EmailMessage \u5bf9\u8c61\u3002\n\n\u793a\u4f8b\u4ee3\u7801\u5982\u4e0b\uff1a\n\n```python\nfrom djangomail import EmailMessage\n\nimport settings\nimport os\nos.environ.setdefault(\"SETTINGS_MODULE\", \"settings\") #\u6b64\u884c\u4ee3\u7801\u4e5f\u53ef\u4ee5\u4e0d\u5199\uff0c\u9ed8\u8ba4\u7684\u6307\u5411\u5c31\u662f settings.py\n\nreceivers = ['somenzz@163.com']\n\nemail = EmailMessage(\n subject='\u5982\u4f55\u4f7f\u7528 djangomail \u53d1\u9001\u9644\u4ef6',\n body='\u8fd9\u91cc\u6709\u9644\u4ef6',\n from_email=settings.DEFAULT_FROM_EMAIL,\n to = receivers,\n reply_to=['897665600@qq.com']\n)\nemail.attach_file(\"/Users/aaron/Documents/python-seven.jpg\", mimetype=\"image/jpeg\")\nemail.attach_file(\"./settings.py\")\nemail.send()\n\n```\n\n\u68c0\u67e5\u4e0b\u90ae\u7bb1\uff1a\n\n![](https://tva1.sinaimg.cn/large/008i3skNgy1grda7uakxij30vw0i874m.jpg)\n\n\n### \u53d1\u9001\u591a\u5f69\u7684 html \u90ae\u4ef6\n\nhtml \u53ef\u4ee5\u663e\u793a\u4e30\u5bcc\u591a\u5f69\u7684\u5185\u5bb9\uff0c\u8fd9\u91cc\u4ee5\u53d1\u9001\u4e00\u4e2a\u542b\u56fe\u7247\u7684 html \u4e3a\u4f8b\u3002\n\n\u9700\u8981\u7528\u5230\u6807\u51c6\u5e93\u91cc\u7684 email \u6a21\u5757\uff0c\u6dfb\u52a0\u56fe\u7247\u4fe1\u606f\uff0c\u793a\u4f8b\u4ee3\u7801\u5982\u4e0b\uff1a\n\n```python\nfrom djangomail import EmailMultiAlternatives\nfrom email.mime.image import MIMEImage\nimport settings\nimport os\nos.environ.setdefault(\"SETTINGS_MODULE\", \"settings\")\n\n\nsubject = 'djangomail \u53d1\u9001\u5e26\u56fe\u7247\u7684 html \u90ae\u4ef6'\n\nbody_html = '''\n<html>\n <body>\n <p>\u300cPython\u4e03\u53f7\u300d\u6bcf\u5468\u5206\u4eab\u4e00\u4e2a\u5c0f\u6280\u5de7 </p>\n <img src=\"cid:qrcode.jpg\" />\n </body>\n</html>\n'''\n\n\nmsg = EmailMultiAlternatives(\n subject,\n body_html,\n from_email=settings.DEFAULT_FROM_EMAIL,\n to=['somenzz@163.com']\n)\n\nmsg.mixed_subtype = 'related'\nmsg.attach_alternative(body_html, \"text/html\")\nimg_dir = 'images/'\nimage = 'qrcode.jpg'\nfile_path = os.path.join(img_dir, image)\nwith open(file_path, 'rb') as f:\n img = MIMEImage(f.read())\n img.add_header('Content-ID', '<{name}>'.format(name=image))\n img.add_header('Content-Disposition', 'inline', filename=image)\nmsg.attach(img)\n\nmsg.send()\n```\n\n\u68c0\u67e5\u4e0b\u90ae\u7bb1\uff0c\u53d1\u73b0\u56fe\u7247\u76f4\u63a5\u663e\u793a\u5728\u4e86\u90ae\u4ef6\u5185\u5bb9\u4e2d\uff1a\n\n![](https://tva1.sinaimg.cn/large/008i3skNgy1grdb1hawpyj31d60s8dhw.jpg)\n\n\n### \u6269\u5c55\n\n\u5176\u5b9e\u4e0d\u6b62\u53d1\u9001\u90ae\u4ef6\uff0c\u901a\u8fc7\u5b9e\u73b0\u81ea\u5df1\u7684 Backend\uff0c\u5c31\u53ef\u4ee5\u5c06\u6d88\u606f\u53d1\u9001\u5230\u4efb\u4f55\u5e73\u53f0\u3002\n\ndjango \u81ea\u5df1\u7684 global_settings \u5176\u5b9e\u5df2\u7ecf\u6709\u4ee5\u4e0b\u914d\u7f6e\uff1a\n\n```python\nEMAIL_BACKEND = 'djangomail.backends.smtp.EmailBackend'\n```\n\n\u53ea\u8981\u6211\u4eec\u6309\u7167 EmailBackend \u7684\u683c\u5f0f\u7f16\u5199\u81ea\u5df1\u7684 Backend \u5c31\u53ef\u4ee5\u5b9e\u73b0\u81ea\u5b9a\u4e49\u7684\u6d88\u606f\u53d1\u9001\uff0c\u6bd4\u5982\u8bf4\u53d1\u9001\u5230\u5fae\u4fe1\u3002\n\n\u7136\u540e\u4fee\u6539 settings.py \u6587\u4ef6\uff0c\u5c06 EMAIL_BACKEND \u914d\u7f6e\u4e3a\u81ea\u5df1\u7684 Backend \u5373\u53ef\u3002 \n\nEmailBackend \u7ee7\u627f\u81ea\u7c7b BaseEmailBackend\uff0c\u5047\u5982\u6211\u4eec\u7f16\u5199\u81ea\u5df1\u7684 MyBackend\uff0c\u53ea\u9700\u8981\u7ee7\u627f BaseEmailBackend \u5b9e\u73b0\u5b83\u7684 send_messages \u65b9\u6cd5\u5373\u53ef\uff1a\n\n```python\ndef send_messages(self, email_messages):\n \"\"\"\n Send one or more EmailMessage objects and return the number of email\n messages sent.\n \"\"\"\n raise NotImplementedError(\n \"subclasses of BaseEmailBackend must override send_messages() method\"\n )\n```\n\n\u6709\u4e2a [server\u9171](https://mp.weixin.qq.com/s/ibBaPbMg202XMEaG-zifVA) \u53ef\u4ee5\u53d1\u9001\u5230\u5fae\u4fe1\uff0c\u4f60\u53ef\u4ee5\u81ea\u5df1\u6269\u5c55\u4e0b\uff0c\u6211\u8fd9\u91cc\u5c31\u4e0d\u5c55\u5f00\u4e86\u3002\n\n\n### \u62a5\u9519\u81ea\u52a8\u53d1\u9001\u90ae\u4ef6\n\n\u5f53\u67d0\u4e2a\u51fd\u6570\u62a5\u9519\uff0c\u4e5f\u5c31\u662f\u629b\u51fa\u5f02\u5e38\u65f6\uff0c\u5982\u679c\u53d1\u9001\u5f02\u5e38\u76f8\u5173\u7684\u5806\u6808\u4fe1\u606f\u90ae\u4ef6\u7ed9\u8fd0\u7ef4\u4eba\u5458\uff0c\u5219\u53ef\u4ee5\u5927\u5927\u63d0\u5347\u5904\u7406\u6548\u7387\u3002\n\n\u5f53\u7136\u4e86\uff0c\u53ef\u4ee5\u6307\u5b9a\u67d0\u4e9b\u5f02\u5e38\uff0c\u53ea\u6709\u629b\u51fa\u8fd9\u7c7b\u5f02\u5e38\u65f6\u624d\u53d1\u90ae\u4ef6\uff0c\u4e5f\u53ef\u4ee5\u5c06\u4e0d\u540c\u7684\u5f02\u5e38\u53d1\u7ed9\u4e0d\u540c\u7684\u4eba\u3002\n\n\u8fd9\u91cc\u6211\u5df2\u7ecf\u505a\u597d\u4e86\u4e00\u4e2a\u88c5\u9970\u5668\uff1asomedecorators\n\n##### \u5b89\u88c5\n\n```sh\npip install somedecorators\n```\n\n##### \u4f7f\u7528\n\n```python\nfrom somedecorators import email_on_exception\nimport os\nos.environ.setdefault(\"SETTINGS_MODULE\", \"settings\")\n\n@email_on_exception(['somenzz@163.com'])\ndef myfunc():\n 1/0\n\nmyfunc()\n```\n\n\u68c0\u67e5\u4e00\u4e0b\u90ae\u7bb1\uff1a\n\n![](https://tva1.sinaimg.cn/large/008i3skNgy1grdbaqr7ooj31e60n43zx.jpg)\n\n##### \u76d1\u63a7\u6307\u5b9a\u7684\u5f02\u5e38\n\n```python\n\nfrom somedecorators import email_on_exception\nimport os\nos.environ.setdefault(\"SETTINGS_MODULE\", \"settings\")\n\nclass Exception1(Exception):\n pass\n\nclass Exception2(Exception):\n pass\n\nclass Exception3(Exception):\n pass\n\n@email_on_exception(['somenzz@163.com'],traced_exceptions = Exception2)\ndef myfunc(args):\n if args == 1:\n raise Exception1\n elif args == 2:\n raise Exception2\n else:\n raise Exception3\n\nmyfunc(2)\n\n```\n\u4e0a\u8ff0\u4ee3\u7801\u53ea\u6709\u5728 raise Exception2 \u65f6\u624d\u4f1a\u53d1\u9001\u90ae\u4ef6\uff1a\n\n![](https://tva1.sinaimg.cn/large/008i3skNgy1grdbh8d2foj31de0l2myd.jpg)\n\n##### \u4e0d\u540c\u7684\u5f02\u5e38\u53d1\u7ed9\u4e0d\u540c\u7684\u4eba\n\n\n```python\n@email_on_exception(['somenzz@163.com'],traced_exceptions = Exception2)\n@email_on_exception(['others@163.com'],traced_exceptions = (Exception1, Exception3))\ndef myfunc(args):\n if args == 1:\n raise Exception1\n elif args == 2:\n raise Exception2\n else:\n raise Exception3\n```\n\n\u662f\u4e0d\u662f\u975e\u5e38\u65b9\u4fbf\uff1f\n\n##### \u5176\u4ed6\u88c5\u9970\u5668\n\n**timeit**\n\n\u8017\u65f6\u7edf\u8ba1\u88c5\u9970\u5668\uff0c\u5355\u4f4d\u662f\u79d2\uff0c\u4fdd\u7559 4 \u4f4d\u5c0f\u6570\n\n\u4f7f\u7528\u65b9\u6cd5\uff1a\n\n```python\nfrom somedecorators import timeit\n@timeit()\ndef test_timeit():\n time.sleep(1)\n\n#test_timeit cost 1.0026 seconds\n\n@timeit(logger = your_logger)\ndef test_timeit():\n time.sleep(1)\n```\n\n**retry**\n\n\u91cd\u8bd5\u88c5\u9970\u5668\u3002\n\n\u5f53\u88ab\u88c5\u9970\u7684\u51fd\u6570\u8c03\u7528\u629b\u51fa\u6307\u5b9a\u7684\u5f02\u5e38\u65f6\uff0c\u51fd\u6570\u4f1a\u88ab\u91cd\u65b0\u8c03\u7528\u3002\n\n\u76f4\u5230\u8fbe\u5230\u6307\u5b9a\u7684\u6700\u5927\u8c03\u7528\u6b21\u6570\u624d\u91cd\u65b0\u629b\u51fa\u6307\u5b9a\u7684\u5f02\u5e38\uff0c\u53ef\u4ee5\u6307\u5b9a\u65f6\u95f4\u95f4\u9694\uff0c\u9ed8\u8ba4 5 \u79d2\u540e\u91cd\u8bd5\u3002\n\ntraced_exceptions \u4e3a\u76d1\u63a7\u7684\u5f02\u5e38\uff0c\u53ef\u4ee5\u4e3a None\uff08\u9ed8\u8ba4\uff09\u3001\u5f02\u5e38\u7c7b\u3001\u6216\u8005\u4e00\u4e2a\u5f02\u5e38\u7c7b\u7684\u5217\u8868\u6216\u5143\u7ec4 tuple\u3002\n\ntraced_exceptions \u5982\u679c\u4e3a None\uff0c\u5219\u76d1\u63a7\u6240\u6709\u7684\u5f02\u5e38\uff1b\u5982\u679c\u6307\u5b9a\u4e86\u5f02\u5e38\u7c7b\uff0c\u5219\u82e5\u51fd\u6570\u8c03\u7528\u629b\u51fa\u6307\u5b9a\u7684\u5f02\u5e38\u65f6\uff0c\u91cd\u65b0\u8c03\u7528\u51fd\u6570\uff0c\u76f4\u81f3\u6210\u529f\u8fd4\u56de\u7ed3\u679c\u3002\n\n\u672a\u51fa\u73b0\u76d1\u63a7\u7684\u5f02\u5e38\u65f6\uff0c\u5982\u679c\u6307\u5b9a\u5b9a\u4e86 reraised_exception \u5219\u629b\u51fa reraised_exception\uff0c\u5426\u5219\u629b\u51fa\u539f\u6765\u7684\u5f02\u5e38\u3002\n\n```python\nfrom somedecorators import retry \n\n@retry(\n times=2,\n wait_seconds=1,\n traced_exceptions=myException,\n reraised_exception=CustomException,\n)\ndef test_retry():\n # time.sleep(1)\n raise myException\n\n\ntest_retry()\n```\n\n### \u5176\u4ed6\u5b9e\u7528\u4e09\u65b9\u5e93\n\n- [dbinterface](https://github.com/somenzz/dbinterface): \u6570\u636e\u5e93\u7edf\u4e00\u8bfb\u3001\u5199\u3001\u5bfc\u51fa\u6587\u4ef6\u63a5\u53e3\uff0c\u9002\u7528\u4e8e\u6570\u636e\u4ed3\u5e93\u7b49\u591a\u6570\u636e\u5e93\u7cfb\u7edf\u5e94\u7528\u3002\u652f\u6301 db2\u3001mysql\uff0cpostgres\u3002\n\n- [transferfile](https://github.com/somenzz/transferfile): \u6587\u4ef6\u4e0a\u4f20\u3001\u4e0b\u8f7d\u63a5\u53e3\uff0c\u9002\u7528\u4e8e\u6587\u4ef6\u5206\u53d1\u7cfb\u7edf\u3002\u652f\u6301 ftp\u3001sftp\u3001scp\u3001rsync\u3002\n\n\n### \u8054\u7cfb\u6211\n\n\u516c\u4f17\u53f7\u300cPython\u4e03\u53f7\u300d\n\n\u5fae\u4fe1\u53f7\u300csomenzz-enjoy\u300d\n",
"bugtrack_url": null,
"license": "MIT",
"summary": "A stand-alone mail module from django",
"version": "0.8",
"project_urls": {
"Homepage": "https://github.com/somenzz/djangomail"
},
"split_keywords": [
"python",
"send",
"email"
],
"urls": [
{
"comment_text": "",
"digests": {
"blake2b_256": "c918019259cf49167c3a52b29ee5cbf51f58634f63148771bc1c494c5b3ca27f",
"md5": "78e3ca1ef9005082809022644ff2af0c",
"sha256": "52f3e3747ae77b9d6fdc7c4b6fe16997dd0c813d6fa89769e288b6606fe313bb"
},
"downloads": -1,
"filename": "djangomail-0.8-py3-none-any.whl",
"has_sig": false,
"md5_digest": "78e3ca1ef9005082809022644ff2af0c",
"packagetype": "bdist_wheel",
"python_version": "py3",
"requires_python": null,
"size": 41136,
"upload_time": "2023-12-21T00:38:08",
"upload_time_iso_8601": "2023-12-21T00:38:08.451157Z",
"url": "https://files.pythonhosted.org/packages/c9/18/019259cf49167c3a52b29ee5cbf51f58634f63148771bc1c494c5b3ca27f/djangomail-0.8-py3-none-any.whl",
"yanked": false,
"yanked_reason": null
},
{
"comment_text": "",
"digests": {
"blake2b_256": "273484452127cf32b20175e44d2f1599b187f7270089142399d1087ca90dc30b",
"md5": "636d3db126f5b812f273791422b293cd",
"sha256": "050ed40fccf631b67c3494547b1bed7d21db4eaf6a0ca988ce8b9501b199fedb"
},
"downloads": -1,
"filename": "djangomail-0.8.tar.gz",
"has_sig": false,
"md5_digest": "636d3db126f5b812f273791422b293cd",
"packagetype": "sdist",
"python_version": "source",
"requires_python": null,
"size": 40543,
"upload_time": "2023-12-21T00:38:10",
"upload_time_iso_8601": "2023-12-21T00:38:10.635461Z",
"url": "https://files.pythonhosted.org/packages/27/34/84452127cf32b20175e44d2f1599b187f7270089142399d1087ca90dc30b/djangomail-0.8.tar.gz",
"yanked": false,
"yanked_reason": null
}
],
"upload_time": "2023-12-21 00:38:10",
"github": true,
"gitlab": false,
"bitbucket": false,
"codeberg": false,
"github_user": "somenzz",
"github_project": "djangomail",
"travis_ci": true,
"coveralls": false,
"github_actions": false,
"tox": true,
"lcname": "djangomail"
}