邮件技术 垃圾邮件识别 文档转文本 MSG-TO-EML

基于内容的垃圾邮件识别 --- 帮助文档

zspam是一款基于内容的邮件打分系统,用于识别垃圾邮件/钓鱼邮件. 最新版本 5.19

能处理各种类型的附件, 包括: 30多种压缩包, 40多种文档, 20多种图片(OCR, 二维码)

支持中文简体,繁体,日文,韩文,越南文,泰文,希伯来文,波斯文,拉丁等文字.   在线体验反垃圾效果

免费版 docker 镜像

docker pull mailutils/antispam

@@@免费版收费版
基于贝叶斯的统计支持支持
基于向量机的统计支持支持
垃圾特征库支持支持
成人特征库,敏感类特征库
自定义多个统计目标支持
样本学习支持
关键字匹配(支持多个自定义目标)支持
系统给出的判定支持
邮件解析结果支持
附件(文档/压缩包)解析结果支持
二维码识别支持支持
OCR文字识别支持支持

特别说明

本系统应该只是邮件反垃圾系统的一个模块,不可能也不应该过滤全部邮件

如下类别的邮件不应该使用本系统(的垃圾判定)

  • 退信
  • 知名可信域名的来信, 如 银行,电商,招聘,服务,平台,公共事业等等

应优先使用其他手段过滤垃圾邮件

  • 黑白名单, rbl, spf, dmarc, 关键字等

服务和端口: 25063, 25065

  • 25063: 垃圾邮件识别服务, 配置 /home/spam/etc/service/spamd.cf
  • 25065: 文档转文本服务, 配置 /home/spam/etc/service/document_text.cf

如果不使用 "文档转文本服务", 可以删除 document_text.cf

如果不使用 "垃圾邮件识别服务", 可以删除 spamd.cf

服务配置: spamd

/home/spam/etc/service/spamd.cf

spam_license =

# 每个进程最多分配内存限制
max-memory = 4G

server-command = /home/spam/bin/spamd

# 服务端口
server-service = 0:25063
# server-service = 127.0.0.1:25063
# server-service = /home/spam/run/spamd.socket

# 进程退出前, 等待多少秒; 0 立即退出
server-stop-on-softstop-after = 10

# 处理多少邮件后, 进程退出; 0 不限制
server-service-max-use = 1000000

# 一个邮件最多处理多少秒, 超时后, 进程退出
server-request-max-run-time = 10

# 日志, syslog 模式
server-log = syslog,mail
# 日志, 输出到标准出错输出
# server-log = 

# 并发进程数
server-proc-count = 3

# 每进程并发线程数
spam_concurrency_limit = 10

# 特征库文件, bayes方法可以可以是多个, svm方法只能有一个
#spam_db = ./db/const.db,./db/const2.db,./db/const9.db
spam_db = /home/spam/db/spam.db

# touch ./run/reloaddb_event_file, 会导致spamd重新加载特征库
# spam_reloaddb_event_file = ./run/reloaddb_event_file

# 其他目标的统计识别(和 spam_db 类似), 支持自定义多个目标
# spam_db_for_testone = ./db/testone111.db
# spam_db_for_xxx = ./db/xxx123.db

# 关键字匹配模块, 支持自定义多个目标
# spam_keyword_for_something = ./db/chengren_keyword,./db/gggg_kd
# spam_keyword_for_antoher = ./db/zhengzhi_keyword

# 是否获取邮件及其附件的解析结果
spam_mail_parser_info = no

# 是否获取系统判定的其他结论
spam_mail_conclusion_info = no

#
# 下面是附件文档处理配置
#

document_text_antispam_mode = 1

# 启用 fork 运行不稳定的模块
document_text_robust_enable = yes

# 资源大小限制, 超过这个限制则不处理
document_text_resource_size_limit = 100M

# 除了 txt, 这些格式的文件作为文本处理, 逗号分割
# document_text_extra_text_formats = js,css,cpp

# 处理资源个数限制
document_text_resource_count_limit = 1024

# 深度限制
document_text_depth_limit = 3

# 处理文档个数限制
document_text_office_convert_count_limit = 12

# 缓存目录, 空表示禁用缓存, 目前只缓存图片处理结果
document_text_cache_pathname = /home/spam/cache_dir_image/

# 一个 pdf, 处理时间限制
document_text_pdf_time_limit = 3

# 一个图片, 处理时间限制
document_text_image_time_limit = 3

# 一个图片, 大小限制
document_text_image_size_limit = 10M

# 一个图片, 限制 (width + height)
document_text_image_width_height_sum_limit = 20000

# 是否启用图片文字识别(OCR), 请注意: 图片文字识别速度很慢
document_text_ocr_enable = no

# 一个图片, OCR处理时间限制(秒)
document_text_ocr_time_limit = 3

# OCR文件个数限制
document_text_ocr_file_count_limit = 3

# OCR文字数量限制
document_text_ocr_char_count_limit = 500

# OCR太慢, 图片宽度限制
document_text_ocr_width_limit = 3000

# OCR太慢, 按高分片处理, 最多分多少片
document_text_ocr_height_slice_limit = 3

# OCR太慢, 分片后, 每片处理的高度为
document_text_ocr_height_per_slice = 100

# document_text_tesseract_lang = chi_sim
# document_text_tesseract_psm = 6
# document_text_tesseract_config_TESSERACT_CONFIG_NAME = TESSERACT_CONFIG_VALUE

# 是否启用图片二维码识别(QRCODE)
document_text_qrcode_enable = yes

# 二维码识别有的时候会有点慢, 限制 (width + height)
document_text_qrcode_width_height_sum_limit = 10000

# QRCODE文件个数限制
document_text_qrcode_file_count_limit = 12

通信协议: spamd

1, 客户端 连接(2种方法):
    1) socket 文件 ./var/socket/spamd
    2) 端口 0:25063                                   ### 默认配置

2, 客户端 输入(2种方法):
    1) score[一个空格]邮件文件路径\r\n                ### 请注意, 服务在docker内运行
    2) score[一个空格]{邮件数据长度}\r\n邮件数据\r\n

3, 服务端 返回(3个情况):
    1) OK[一个空格]得分\r\n
    2) OK[一个空格]得分 {额外数据(JSON)的长度}\r\nJSON数据\r\n
    3) ERR[一个空格]error_msg\r\n

4, 客户端 继续(2种):
    1)关闭连接
    2)回到 2

系统, 容器

日志

所有的日志输出默认都是 SYSLOG, MAIL

本镜像系统没有提供日志服务, 见docker的参数 -v /dev/log:/dev/log

启动容器(服务)

docker run --name container_name -d -p 25062:25062 -p 25063:25063 -p 25065:25065 -v /dev/log:/dev/log image_name

启动容器, 但不想启动服务

docker run --name container_name image_name /bin/sleep 36500d

不重启容器, 重新加载特征库

docker exec -it container_name /home/spam/bin/master.sh reload

镜像内操作系统

本镜像基于操作系统: debian 11.6

/bin/zy_spamc 的使用

docker exec -it container_name /bin/zy_spamc --help

本文提到的zy_spamc命令都是在容器内执行, 需要注意路径的问题

大部分情况需要修改参数, 风格为:

zy_spamc [ -config config_file [ -config config_file ] ] [ -some_key some_value [ -some_key1 some_value1 ] ] \
    do_something do_something_arg1 ... \
    [ -config config_file [ -config config_file ] ] [ -some_key some_value [  -some_key1 some_value1 ] ]

# 作为一个命令, 配置文件spamd.cf中的配置项都可以作为参数使用

# 如果参数中出现(可以多组) -config somepath.cf, 那么会立即加载配置文件somepath.cf

# 遵循规则: 后加载的配置项覆盖先加载的配置项

# 遵循规则: 命令行上的配置项覆盖配置文件中的配置项

/home/spam/bin/test_spamd.sh 的使用

命令 /home/spam/bin/test_spamd.sh 用于在线测试 spamd 服务

可以在容器外执行

# docker cp container_name:/home/spam/bin/test_spamd.sh /somepath/
./test_spamd.sh [ 127.0.0.1:25063 ] eml_file [ eml_file1 [ ... ] ] [ eml_dir [ ...] ]

关键字模块

服务配置

关键字匹配模块, 支持自定义多个目标

支持配置多个"关键字文件"

在 spamd.cf 中配置

# spam_keyword_for_something = var/spamdb/chengren_keyword,var/spamdb/gggg_kd
# spam_keyword_for_antoher = var/spamdb/zhengzhi_keyword
# spam_keyword_for_testone = var/spamdb/testone

服务结论

结论在服务返回的 JSON 中, 形如:

{
    "keyword": [
        {"for":"something","part":"TEXT","word":"匹配的关键字"},
        {"for":"antoher","part":"SUBJECT","word":"匹配的关键字"},
        {"for":"testone","part":"SUBJECT","word":"匹配的关键字"}
    ]
}

如果没有配置, 或所有的关键都不存在, 则 JSON 中可能没有 "keyword" 属性

关键字文件内容(例子)

### 是文本
关键字第一个
 关键字第二个忽略行首尾空格
第三个   关键 字
### 行首为三个连续的 # 符号, 则忽略
### 忽略空行
### 不支持任何转义

编译

如果关键字文件有10万行以上,建议先编译再使用

zy_spamc keyword_compile 第一个关键字文件 [ 第二个 [ 第三个 ... ] ] 目标文件

命令行测试, 本地

zy_spamc keyword 关键字文件1,关键字文件2[, ...] 邮件或邮件目录

系统判定的其他结论

服务配置

在spamd.cf 中配置

是否获取系统判定的其他结论

spam_mail_conclusion_info = yes

服务结论

结论在服务返回的 JSON 中, 形如:

{
	"conclusion": [
		"TO_MAIL_IN_TO_NAME",
		"MIME_ONLY_HTML",
		"HTML_TABLE_WORD_TD_COUNT:120",
		"SUBJECT_ONE_TOKEN",
		"HEADER_NO_MAILER_USER_AGENT"
	]
}

结论列表

ATT_COUNT:数量附件个数(不包含内嵌图片附件)
例子, 12个附件, ATT_COUNT:12
MAILER:FOXMAILX-Mailer 是 foxmail
MAILER:OUTLOOKX-Mailer 是 outlook
MIME_ONLY_HTML仅有 HTML
MIME_ONLY_PLAIN仅有 PLAIN
OUTLOOK_ONLY_HTMOUTLOOK, 仅有 HTML, 基本可以判垃圾
OUTLOOK_ONLY_PLAINOUTLOOK, 仅有 PLAIN, 基本可以判垃圾
HEADER_REFERENCES_COUNT:数量References 里条目数
FROM_MAIL:发件人发件人地址
FROM_DOMAIN:发件人域名发件人地址的域名
FROM_DOMAIN_NONE发件人没域名
FROM_MAIL_EMPTY发件人地址为空, 或不存在 From:
FROM_DOMAIN_IN_MESSAGE_IDFrom的域名出现在 Message-id 中
FROM_DOMAIN_NOT_IN_MESSAGE_IDFrom的域名没出现在 Message-id 中
FROM_DOMAIN_NOT_IN_TO_DOMAIN From的域名出现在 to 的域名 中
FROM_DOMAIN_NOT_IN_TO_DOMAINFROM_DOMAIN 没出现在 TO_DOMAIN
FROM_DOMAIN_NE_SENDER_DOMAINFrom 的域名 和 X-Sender的域名不同
FROM_DOMAIN_EQ_SENDER_DOMAINFrom 的域名 和 X-Sender的域名相同
FROM_IN_TO发件人在收件人中
FROM_IN_TO_NAME发件人的地址在收件人的名字中
FROM_MAIL_IN_BODY发件人地址在正文中
FROM_MAIL_NOT_IN_BODY发件人地址不在正文中
FROM_NAME_EMPTY发件人没名字, 或不存在 From:
FROM_NAME_NO_EQ(原始)发件人名没有 =?
FROM_NAME_DOMAIN_NE_FROM_DOMAIN   发件人名字的域名 和 发件人的域名不同
FROM_NAME_DOMAIN_EQ_FROM_DOMAIN/FROM_NAME_NE_FROM
发件人名字的域名 和 发件人的域名相同/同时/发件人的名字和发件人不同
FROM_NE_RECEIPTFrom 和 Disposition-Notification-To 不同
FROM_EQ_RECEIPTFrom 和 Disposition-Notification-To 相同
FROM_NE_REPLY_TOFrom和 Replay-To 不同
FROM_EQ_REPLY_TOFrom和 Replay-To 相同
RECEIPT_NE_REPLY_TODisposition-Notification-To 和 Reply-To 不同
RECEIPT_EQ_REPLY_TODisposition-Notification-To 和 Reply-To 相同
SENDER_NE_RECEIPTX-Sender 和 Disposition-Notification-To 不同
SENDER_EQ_RECEIPTX-Sender 和 Disposition-Notification-To 相同
SENDER_NE_REPLY_TOX-Sender 和 Reply-To 不同
SENDER_EQ_REPLY_TOX-Sender 和 Reply-To 相同
TO_COUNT:数量To 个数
TO_ONE/TO_MAIL_EMPTY一个 TO, 且没有邮件地址
TO_ONE/FROM_EQ_TO一个 TO, 且其地址和 From 的地址相同
TO_UID_IN_TO_NAMETo 邮件地址@前面的部分出现在名称中
TO_MAIL_IN_TO_NAMETo 邮件地址出现在名称中
TO_MAIL:收件人地址收件人地址
TO_DOMAIN:收件人域名收件人地址的域名
TO_MAIL_NOT_IN_TO_NAME/TO_DOMAIN_IN_TO_NAME   To 邮件地址没出现在名称中, 且域名出现在名称中
TO_DOMAIN_COUNTTo 中不同域名的个数
TO(FROM_DOMAIN)_COUNT和 From 的域名同域的 To 的个数
TO_DOMAIN_ONE/FROM_DOMAIN_EQ_TO_DOMAIN收件人中只有一个域, 且和发件人域相同
FROM_DOMAIN_NOT_IN_TO_DOMAINFrom 域没出现在 To 中
SUBJECT_FWD_RE主题开始字符串是 RW/FWD/RE/转发/回复/答复/轉寄/回覆
SUBJECT_LEN:长度主题长度
SUBJECT_IN_BODY主题出现在正文
SUBJECT_ONE_TOKEN主题只有一个TOKEN
SUBJECT_NO_EQ原始主题没有 =?
SUBJECT_A1B2C_TOKEN主题中存在类似字段 ABC123D56EFG 或 12BDAF6756SGFA8013
SUBJECT_A1B2_TOKEN主题中存在类似字段 ABC123DSFSDF56 或 12BDAF6756SGFA
BODY_LEN:长度正文长度(去掉 html 标签)
BODY_NCR_COUNT:数量正文中 ncr 个数
INLINE_IMAGE_COUNT:数量内嵌图片附件个数
INLINE_IMAGE_UNKNOWN_TYPEsize最大的内嵌图片的真实类型未知
INLINE_IMAGE_HEIGHT:数量size最大的内嵌图片附件的高度
INLINE_IMAGE_WIDTH:数量size最大的内嵌图片附件的宽度
ATT_COUNT:数量附件个数(不包含内嵌图片附件)
ATT_SUFFIX:附件名后缀附件名的后缀(文件类型)
ATT_NAME_A1B2C_TOKEN附件名中存在类似字段 ABC123D56EFG 或 12BDAF6756SGFA8013
ATT_NAME_A1B2_TOKEN附件名中存在类似字段 ABC123DSFSDF56 或 12BDAF6756SGFA
ATT_NAME_IN_BODY附件名出现在正文
ATT_NAME_IN_SUBJECT附件名出现在主题
ATT_NAME_LEN_EQ0附件名长度为 0
ATT_NAME_LEN_GT0_LT3附件名长度为 大于 0, 小于 3
ATT_NAME_LEN_GT256附件名长度为 大于 256
ATT_NAME_ONE_TOKEN附件名只有一个字段
ATT_NAME_CONSECUTIVE_BLANK_GT10附件名连续的空格(或 .)超过 10 个
FIRST_TO_IN_HTML_ATT第一个收件人出现在HTML类型的附件中
URL_COUNT:数量URL个数
HTML_URL_AT网址中有字符
FIRST_TO_IN_URL网址中有第一个收件人地址
HTML_URL_NO_MAILTO网址中没有 mailto:
HTML_URL_CONTENT_MISMATCHEDA(AREA)标签的显示名称是url地址,且和href不一样
HTML_DATA_IMAGEhtml有内嵌图片(data:image)
HTML_ATTRIBUTE_NOT_ABC存在非字母的 HTML 属性
HTML_FONT_SPECIAL存在特殊的干扰阅读的html属性
HTML_FONT_COLOR_COUNT:数量有 color 属性的 font 标签的个数
HTML_FONT_SIZE0_COUNT:数量size 为 0 的 font 标签个数
HTML_FONT_SIZE1_COUNT:数量size 为 1 的 font 标签个数
HTML_FONT_SIZE2_COUNT:数量size 为 2 的 font 标签个数
HTML_FONT_SIZE5_COUNT:数量size 为 5 的 font 标签个数
HTML_FONT_SIZE6_COUNT:数量size 为 6 的 font 标签个数
HTML_FONT_SIZE7_COUNT:数量size 为 7 的 font 标签个数
HTML_STYLE_COLOR_COUNT:数量style 中有 color 属性的标签的个数
HTML_STYLE_DISPLAYstyle 中有 display 属性
HTML_STYLE_POSITION_ABSOLUTEstyle 中有 position:absolute
HTML_STYLE_SIZE0_COUNT:数量style 中有 size 为 0 属性的标签的个数
HTML_STYLE_SIZE_COUNT:数量style 中有 size 属性的标签的个数
HTML_TABLE_WORD_TD_COUNT:数量table 字, 每行 td 个数(至少30)
HTML_TAG_FORM有 form 标签
HTML_TAG_FRAME有 frame 标签
HTML_TAG_SCRIPT有 script 标签
HTML_IMAGE_WIDTH_1img 的 width 属性值为 1
HTML_IMAGE_HEIGHT_1img 的 height 属性值为 1
HTML_IMAGE_WIDTH_HEIGHT_1img 的 width/height 属性值都为 1
A_weak_malware低风险附件文档, 如 html, cab, jar
A_general_malware一般风险附件文档, 如 ace, arj, iso, r00
A_high_malware高风险附件文档, 如 bat, com, exe, pif, scr, vbs
A_forged_malware伪造的高风险附件文档, 如 abcdef.pdf.exe
A_malicious附件文档里有可能含有(恶意)脚本
A_detected附件文档类型是探测得到的, 如 abcdef.zip 实际是 abcdef.rar
A_html_refresh附件文档是html, 且含有 refresh 指令
A_html_tag_frame附件文档是html, 且含有 iframe 标签
A_html_tag_script附件文档是html, 且含有 script 标签
A_html_tag_form附件文档是html, 且含有 form标签
A_html_to_in_url附件文档是html, 且第一个收件人出现在url中
A_html_at_in_url附件文档是html, 且 “@” 出现在url中
A_html_url_file附件文档是html, 且 url 协议是 file://
A_html_data_image附件文档是html, 且 url 中含有图片
A_html_css_data_image附件文档是html, 且 css 中含有图片
A_html_url_count:数量附件文档是html, url的数量
A_html_image_url_count附件文档是html, 图片url的数量
A_only_one_high_malware_in_tar附件是压缩包, 且只含有一个文件, 且这个文件是高风险文件
A_only_one_file_in_tar附件是压缩包, 且只含有一个文件
A_first_to_in_att第一个收件人在附件中
A_att_name_blank_gt10附件名含有超过10个连续空格或 "."
A_encrypted有加密类型的附件
ATT_IMAGE_QRCODE附件图片中含有二维码
INLINE_IMAGE_QRCODE内嵌图片中含有二维码

邮件及其附件解析结果

服务配置

是否获取邮件及其附件的解析结果

spam_mail_parser_info = yes

服务结论

结论在服务返回的 JSON 中, 形如:

{
    "parser": {
        "subject_utf8":"行政部收",
        "from":{"address":xxx@xxx.com","name_utf8":"xxx"},
        "to":[
            {"address":xxx@xxx.com","name_utf8":"xxx"},
            {"address":xxx2@xxx.com","name_utf8":"xxx2"}
        ],
        "text_mime":[
            {
                "charset":"utf-8",
                "content":"文本<\/html>",
                "encoding":"quoted-printable",
                "readable_content":"去除html标签后的可读可显示的文本",
                "size":3147,
                "type":"text\/html",
                "urls":["html中的网址","网址2"]
            }
        ],
        "attachment_mime":[
            {
                "charset":"",
                "doc_data":{这里的结构相当复杂, 见 http://linuxmail.cn/document_text/help.html },
                "encoding":"base64",
                "size":7756,
                "type":"application\/octet-stream",
                "name_utf8":"可读的附件名"
            }
        ]
    }
}

客户端工具: 贝叶斯

zy_spamc 工具, bayes 方法的使用

score, 测试信件得分 离线

获得邮件a.eml, b.eml, 和 eml_path1下所有文件(假设都是邮件) 的得分

zy_spamc bayes score ./a.db,./b.db,./c.db a.eml b.eml emlpath1
zy_spamc bayes score ./a.db a.eml b.eml emlpath1

score, 测试信件得分 在线

获得邮件a.eml, b.eml, 和 eml_path1下所有邮件 的得分

zy_spamc bayes score 0:25063 a.eml b.eml emlpath1

ham, 训练正常信件 离线

训练a.eml, b.eml, c.eml, eml_path1, eml_path2 下所有的邮件为正常邮件

zy_spamc bayes ham ./train.db a.eml b.eml eml_path1
zy_spamc bayes ham ./train.db c.eml eml_path2

提示, train.db 可以不存在, 程序会自动创建

提示, train.db是bdb格式, 不能用const格式

spam, 训练垃圾邮件 离线

训练x.eml, y.eml, z.eml, eml_path8, eml_path9 下所有的邮件为垃圾邮件

zy_spamc bayes spam ./train.db x.eml z.eml eml_path9
zy_spamc bayes spam ./train.db y.eml
zy_spamc bayes spam ./train.db eml_path8

merge_db, 合并数据库 离线

合并a.db, b.db, c.db 到 train.db

zy_spamc bayes merge_db a.db train.db
zy_spamc bayes merge_db b.db train.db
zy_spamc bayes merge_db c.db train.db

convert_db, 数据库格式转换 离线

把train.db 转换为const.db

const.db是系统自带的只读数据库格式(速度快)

zy_spamc bayes convert_db train.db const.db

clear_db 数据库格式转换 离线

同 convert_db, 且清理意义不大的 token

zy_spamc bayes clear_db train.db const.db

客户端工具: 向量机

score, 测试信件得分

获得邮件a.eml, b.eml, 和 eml_path1下所有邮件 的得分

./bin/zy_spamc svm score ./svm.db a.eml b.eml emlpath1

score, 测试信件得分 在线

获得邮件a.eml, b.eml, 和 eml_path1下所有邮件的得分

./bin/zy_spamc svm score 0:25063 a.eml b.eml emlpath1

ham, 训练正常信件

训练a.eml, b.eml, c.eml, eml_path1, eml_path2 下所有的邮件为正常邮件

./bin/zy_spamc svm ham ./flat.txt a.eml b.eml eml_path1

./bin/zy_spamc svm ham ./flat.txt c.eml eml_path2

提示, flat.txt 可以不存在, 程序会自动创建

spam, 训练垃圾邮件

训练x.eml, y.eml, z.eml, eml_path8, eml_path9 下所有的邮件为垃圾邮件

./bin/zy_spamc svm spam ./flat.txt x.eml z.eml eml_path9
./bin/zy_spamc svm spam ./flat.txt y.eml
./bin/zy_spamc svm spam ./flat.txt eml_path8

model 编译为 SVM 模型

把 flat.txt 编译为SVM模型, 存为 svm.db, 且清理意义不大的 token

./bin/zy_spamc svm model flat.txt svm.db

邮件文件(目录)

邮件文件路径

形如: /opt/mail/storage/some1.eml

系统假设: 客户端提供的任何文件都是邮件且可读

邮件文件目录

形如: /opt/mail/storage/

系统假设: 此目录下, 所有的(递归)文件都是邮件且可读

反垃圾得分

形如 0.700268

介于0.000000 ~ 1.000000 之间

越接近 1.0, 是垃圾邮件的可能性越大

根据作者实际经验,大于0.7的可以判定垃圾邮件,小于0.4为可以判定正常邮件

SVM 模式下, 得分只有两个值 0.000000 和 1.000000

京ICP备18054515号-2 eli960@qq.com gitee.com