1"use strict";(self.webpackChunkrspamd_docs=self.webpackChunkrspamd_docs||[]).push([[2105],{28453:(e,s,n)=>{n.d(s,{R:()=>i,x:()=>o});var r=n(96540);const d={},l=r.createContext(d);function i(e){const s=r.useContext(l);return r.useMemo((function(){return"function"==typeof e?e(s):{...s,...e}}),[s,e])}function o(e){let s;return s=e.disableParentContext?"function"==typeof e.components?e.components(d):e.components||d:i(e.components),r.createElement(l.Provider,{value:s},e.children)}},35768:(e,s,n)=>{n.r(s),n.d(s,{assets:()=>t,contentTitle:()=>o,default:()=>h,frontMatter:()=>i,metadata:()=>r,toc:()=>c});const r=JSON.parse('{"id":"modules/known_senders","title":"Known senders module","description":"The known_senders module maintains a Redis-backed set of hashed sender addresses for a configured set of domains. It lets you:","source":"@site/docs/modules/known_senders.md","sourceDirName":"modules","slug":"/modules/known_senders","permalink":"/modules/known_senders","draft":false,"unlisted":false,"editUrl":"https://github.com/rspamd/docs.rspamd.com/edit/master/docs/modules/known_senders.md","tags":[],"version":"current","frontMatter":{"title":"Known senders module"},"sidebar":"docs","previous":{"title":"IP Score module","permalink":"/modules/ip_score"},"next":{"title":"Mailing lists module","permalink":"/modules/maillist"}}');var d=n(74848),l=n(28453);const i={title:"Known senders module"},o="Known senders module",t={},c=[{value:"How it works",id:"how-it-works",level:2},{value:"Configuration",id:"configuration",level:2},{value:"Symbols",id:"symbols",level:2},{value:"Requirements",id:"requirements",level:2},{value:"Notes",id:"notes",level:2}];function a(e){const s={a:"a",code:"code",h1:"h1",h2:"h2",header:"header",li:"li",ol:"ol",p:"p",pre:"pre",strong:"strong",table:"table",tbody:"tbody",td:"td",th:"th",thead:"thead",tr:"tr",ul:"ul",...(0,l.R)(),...e.components};return(0,d.jsxs)(d.Fragment,{children:[(0,d.jsx)(s.header,{children:(0,d.jsx)(s.h1,{id:"known-senders-module",children:"Known senders module"})}),"\n",(0,d.jsxs)(s.p,{children:["The ",(0,d.jsx)(s.code,{children:"known_senders"})," module maintains a Redis-backed set of hashed sender addresses for a configured set of domains. It lets you:"]}),"\n",(0,d.jsxs)(s.ul,{children:["\n",(0,d.jsx)(s.li,{children:"mark messages from previously seen senders as known"}),"\n",(0,d.jsx)(s.li,{children:"flag first-time senders from those domains"}),"\n",(0,d.jsxs)(s.li,{children:["verify inbound replies using data produced by the ",(0,d.jsx)(s.a,{href:"/modules/replies",children:(0,d.jsx)(s.code,{children:"replies"})})," module (global and per-sender local checks)"]}),"\n"]}),"\n",(0,d.jsx)(s.p,{children:"Requires Redis; optional support for RedisBloom."}),"\n",(0,d.jsx)(s.h2,{id:"how-it-works",children:"How it works"}),"\n",(0,d.jsxs)(s.ol,{children:["\n",(0,d.jsxs)(s.li,{children:["For SMTP and MIME ",(0,d.jsx)(s.code,{children:"From"})," addresses belonging to the configured ",(0,d.jsx)(s.code,{children:"domains"}),", Rspamd hashes the full address and checks storage:\n",(0,d.jsxs)(s.ul,{children:["\n",(0,d.jsxs)(s.li,{children:["with ",(0,d.jsx)(s.code,{children:"use_bloom = false"}),": a Redis ZSET named by ",(0,d.jsx)(s.code,{children:"redis_key"})]}),"\n",(0,d.jsxs)(s.li,{children:["with ",(0,d.jsx)(s.code,{children:"use_bloom = true"}),": a RedisBloom filter named by ",(0,d.jsx)(s.code,{children:"redis_key"})]}),"\n"]}),"\n"]}),"\n",(0,d.jsxs)(s.li,{children:["If found, Rspamd inserts ",(0,d.jsx)(s.code,{children:"symbol"})," (default ",(0,d.jsx)(s.code,{children:"KNOWN_SENDER"}),"). If not found, it inserts ",(0,d.jsx)(s.code,{children:"symbol_unknown"})," and stores the sender, trimming to ",(0,d.jsx)(s.code,{children:"max_senders"}),"."]}),"\n",(0,d.jsxs)(s.li,{children:["If the ",(0,d.jsx)(s.a,{href:"/modules/replies",children:(0,d.jsx)(s.code,{children:"replies"})})," module is enabled, two additional checks are available:\n",(0,d.jsxs)(s.ul,{children:["\n",(0,d.jsxs)(s.li,{children:[(0,d.jsx)(s.code,{children:"symbol_check_mail_global"}),": sender exists in the global replies set"]}),"\n",(0,d.jsxs)(s.li,{children:[(0,d.jsx)(s.code,{children:"symbol_check_mail_local"}),": at least one of current recipients exists in the sender\u2019s local replies set"]}),"\n"]}),"\n"]}),"\n"]}),"\n",(0,d.jsxs)(s.p,{children:["Result options indicate which key matched, e.g. ",(0,d.jsx)(s.code,{children:"smtp:<hash>"})," or ",(0,d.jsx)(s.code,{children:"mime:<hash>"}),"."]}),"\n",(0,d.jsx)(s.h2,{id:"configuration",children:"Configuration"}),"\n",(0,d.jsxs)(s.p,{children:["Add configuration to ",(0,d.jsx)(s.code,{children:"/etc/rspamd/local.d/known_senders.conf"})," (or configure Redis globally):"]}),"\n",(0,d.jsx)(s.pre,{children:(0,d.jsx)(s.code,{className:"language-hcl",children:'known_senders {\n enabled = true;\n\n # Redis (can be configured globally as well)\n #servers = 127.0.0.1:6379;\n\n # Domains to track senders (map or list)\n domains = "https://maps.rspamd.com/freemail/free.txt.zst";\n\n # Storage\n use_bloom = false; # requires RedisBloom if true\n redis_key = "rs_known_senders";\n max_senders = 100000; # max elements kept in set/filter\n max_ttl = 30d; # default 30 days; applies to non-Bloom (ZSET) storage\n\n # Symbols\n symbol = "KNOWN_SENDER";
1\n symbol_unknown = "UNKNOWN_SENDER";\n symbol_check_mail_global = "INC_MAIL_KNOWN_GLOBALLY";\n symbol_check_mail_local = "INC_MAIL_KNOWN_LOCALLY";\n\n # Replies-related (must match settings in the replies module when changed)\n sender_prefix = "rsrk";\n sender_key_global = "verified_senders";\n sender_key_size = 20; # applies to global reply-set keys only; local keys are always 8 chars\n max_recipients = 15; # recipients to verify for local set\n\n # Optional privacy for reply sender before hashing\n reply_sender_privacy = false;\n reply_sender_privacy_alg = "blake2";\n reply_sender_privacy_prefix = "obf";\n reply_sender_privacy_length = 16;\n}\n'})}),"\n",(0,d.jsx)(s.h2,{id:"symbols",children:"Symbols"}),"\n",(0,d.jsx)(s.p,{children:"The module registers the following symbols with hard-coded default scores:"}),"\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n",(0,d.jsxs)(s.table,{children:[(0,d.jsx)(s.thead,{children:(0,d.jsxs)(s.tr,{children:[(0,d.jsx)(s.th,{children:"Symbol"}),(0,d.jsx)(s.th,{children:"Option"}),(0,d.jsx)(s.th,{children:"Default score"}),(0,d.jsx)(s.th,{children:"Meaning"})]})}),(0,d.jsxs)(s.tbody,{children:[(0,d.jsxs)(s.tr,{children:[(0,d.jsx)(s.td,{children:(0,d.jsx)(s.code,{children:"KNOWN_SENDER"})}),(0,d.jsx)(s.td,{children:(0,d.jsx)(s.code,{children:"symbol"})}),(0,d.jsx)(s.td,{children:"-1.0"}),(0,d.jsx)(s.td,{children:"sender already known"})]}),(0,d.jsxs)(s.tr,{children:[(0,d.jsx)(s.td,{children:(0,d.jsx)(s.code,{children:"UNKNOWN_SENDER"})}),(0,d.jsx)(s.td,{children:(0,d.jsx)(s.code,{children:"symbol_unknown"})}),(0,d.jsx)(s.td,{children:"+0.5"}),(0,d.jsx)(s.td,{children:"first-time sender stored now"})]}),(0,d.jsxs)(s.tr,{children:[(0,d.jsx)(s.td,{children:(0,d.jsx)(s.code,{children:"INC_MAIL_KNOWN_GLOBALLY"})}),(0,d.jsx)(s.td,{children:(0,d.jsx)(s.code,{children:"symbol_check_mail_global"})}),(0,d.jsx)(s.td,{children:"-1.0"}),(0,d.jsx)(s.td,{children:"sender verified by global replies set"})]}),(0,d.jsxs)(s.tr,{children:[(0,d.jsx)(s.td,{children:(0,d.jsx)(s.code,{children:"INC_MAIL_KNOWN_LOCALLY"})}),(0,d.jsx)(s.td,{children:(0,d.jsx)(s.code,{children:"symbol_check_mail_local"})}),(0,d.jsx)(s.td,{children:"-1.0"}),(0,d.jsx)(s.td,{children:"at least one recipient verified by the sender\u2019s local replies set"})]})]})]}),"\n",(0,d.jsx)(s.p,{children:"Override these scores in your metrics configuration as needed."}),"\n",(0,d.jsx)(s.h2,{id:"requirements",children:"Requirements"}),"\n",(0,d.jsxs)(s.ul,{children:["\n",(0,d.jsxs)(s.li,{children:[(0,d.jsx)(s.strong,{children:"Redis"}),": configure Redis servers globally or per-module, see ",(0,d.jsx)(s.a,{href:"/configuration/redis",children:"Redis configuration"})]}),"\n",(0,d.jsxs)(s.li,{children:[(0,d.jsx)(s.strong,{children:"RedisBloom (optional)"}),": required if ",(0,d.jsx)(s.code,{children:"use_bloom = true"}),". Enable in Redis, e.g. in ",(0,d.jsx)(s.code,{children:"redis.conf"}),":"]}),"\n"]}),"\n",(0,d.jsx)(s.pre,{children:(0,d.jsx)(s.code,{children:"loadmodule /path/to/redisbloom.so\n"})}),"\n",(0,d.jsx)(s.h2,{id:"notes",children:"Notes"}),"\n",(0,d.jsxs)(s.ul,{children:["\n",(0,d.jsxs)(s.li,{children:["If you change ",(0,d.jsx)(s.code,{children:"sender_prefix"})," in ",(0,d.jsx)(s.code,{children:"local.d/replies.conf"}),", change it here as well to keep sets aligned."]}),"\n",(0,d.jsxs)(s.li,{children:[(0,d.jsx)(s.code,{children:"domains"})," accepts the same map forms used elsewhere (file/HTTP/HTTPS, compressed maps, etc.)."]}),"\n",(0,d.jsxs)(s.li,{children:[(0,d.jsx)(s.code,{children:"sender_key_size"})," (default 20) controls the length of the ",(0,d.jsx)(s.strong,{children:"global"})," reply-set key only. Local per-sender reply-set keys are always truncated to 8 characters regardless of this setting."]}),"\n"]})]})}function h(e={}){const{wrapper:s}={...(0,l.R)(),...e.components};return s?(0,d.jsx)(s,{...e,children:(0,d.jsx)(a,{...e})}):a(e)}}}]);
Line numbers count LF bytes from the start of the resource, as the search results do. Vendor segments are library code the classifier recognised; they are stored but not indexed. Bytes are shown as Latin1 characters, one per byte.