PageSourceSearch

https://docs.rspamd.com/assets/js/2e6058df.661d1b9b.js

js rspamd.com collected 2026-10-02 02:30:04 UTC 9,683 bytes, 1 lines download raw bytes

1"use strict";(self.webpackChunkrspamd_docs=self.webpackChunkrspamd_docs||[]).push([[4507],{28453:(e,n,s)=>{s.d(n,{R:()=>t,x:()=>l});var r=s(96540);const i={},d=r.createContext(i);function t(e){const n=r.useContext(d);return r.useMemo((function(){return"function"==typeof e?e(n):{...n,...e}}),[n,e])}function l(e){let n;return n=e.disableParentContext?"function"==typeof e.components?e.components(i):e.components||i:t(e.components),r.createElement(d.Provider,{value:n},e.children)}},59177:(e,n,s)=>{s.r(n),s.d(n,{assets:()=>c,contentTitle:()=>l,default:()=>h,frontMatter:()=>t,metadata:()=>r,toc:()=>o});const r=JSON.parse('{"id":"modules/spf","title":"SPF module","description":"The SPF module checks the sender\'s SPF Many mail providers use SPF records to determine eligible hosts for sending email on a specific domain. There are various ways to create and use SPF records, but they all primarily verify the sender\'s domain and IP.","source":"@site/docs/modules/spf.md","sourceDirName":"modules","slug":"/modules/spf","permalink":"/modules/spf","draft":false,"unlisted":false,"editUrl":"https://github.com/rspamd/docs.rspamd.com/edit/master/docs/modules/spf.md","tags":[],"version":"current","frontMatter":{"title":"SPF module"},"sidebar":"docs","previous":{"title":"Spamtrap module","permalink":"/modules/spamtrap"},"next":{"title":"SURBL module","permalink":"/modules/surbl"}}');var i=s(74848),d=s(28453);const t={title:"SPF module"},l="SPF module",c={},o=[{value:"Principles of work",id:"principles-of-work",level:2},{value:"Configuration options",id:"configuration-options",level:2},{value:"Symbols",id:"symbols",level:2},{value:"Example configuration",id:"example-configuration",level:2},{value:"Using SPF with forwarding",id:"using-spf-with-forwarding",level:2}];function a(e){const n={a:"a",code:"code",h1:"h1",h2:"h2",header:"header",p:"p",pre:"pre",table:"table",tbody:"tbody",td:"td",th:"th",thead:"thead",tr:"tr",...(0,d.R)(),...e.components};return(0,i.jsxs)(i.Fragment,{children:[(0,i.jsx)(n.header,{children:(0,i.jsx)(n.h1,{id:"spf-module",children:"SPF module"})}),"\n",(0,i.jsxs)(n.p,{children:["The SPF module checks the sender's ",(0,i.jsx)(n.a,{href:"http://www.open-spf.org/",children:"SPF"})," Many mail providers use SPF records to determine eligible hosts for sending email on a specific domain. There are various ways to create and use SPF records, but they all primarily verify the sender's domain and IP."]}),"\n",(0,i.jsxs)(n.p,{children:["A specific scenario involves automated messages from the special mailer daemon address: ",(0,i.jsx)(n.code,{children:"<>"}),". In this case, Rspamd utilizes ",(0,i.jsx)(n.code,{children:"HELO"})," to retrieve domain information according to the standard."]}),"\n",(0,i.jsx)(n.h2,{id:"principles-of-work",children:"Principles of work"}),"\n",(0,i.jsxs)(n.p,{children:["When used correctly, ",(0,i.jsx)(n.code,{children:"SPF"})," can be a valuable tool. However, it often becomes vulnerable in situations where a message is redirected or modified by mailing list software."]}),"\n",(0,i.jsx)(n.p,{children:"Furthermore, numerous mail providers lack a proper understanding of this technology, resulting in the misuse of SPF techniques. As a result, the scores for SPF symbols in Rspamd tend to be relatively low."}),"\n",(0,i.jsxs)(n.p,{children:["The cache follows the principle of ",(0,i.jsx)(n.code,{children:"least recently used"})," expiration, meaning that the lifetime of each cached item is determined by the time to live of the corresponding DNS record."]}),"\n",(0,i.jsx)(n.p,{children:"To configure the SPF module, you have the option to manually specify the cache size and maximum expiration time. Additionally, you can define parameters such as the maximum number of recursive DNS subrequests (including chain length), the maximum count of DNS requests per record, the minimum TTL enforced for all elements in SPF records, and the ability to disable all IPv6 lookups."}),"\n",(0,i.jsx)(n.h2,{id:"configuration-options",children:"Configuration options"}),"\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\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n",(0,i.jsxs)(n.table,{children:[(0,i.jsx)(n.thead,{children:(0,i.jsxs)(n.tr,{children:[(0,i.jsx)(n.th,{children:"Option"}),(0,i.jsx)(n.th,{children:"Default"}),(0,i.jsx)(n.th,{children:"Description"})]})}),(0,i.jsxs)(n.tbody,{children:[(0,i.jsxs)(n.tr,{children:[(0,i.jsx)(n.td,{children:(0,i.jsx)(n.code,{children:"spf_cache_size"})}),(0,i.jsx)(n.td,{children:"2048"}),(0,i.jsx)(n.td,{children:"Number of elements in the LRU cache of parsed SPF records"})]}),(0,i.jsxs)(n.tr,{children:[(0,i.jsx)(n.td,{children:(0,i.jsx)(n.code,{children:"spf_cache_expire"})}),(0,i.jsx)(n.td,{children:"1d"}),(0,i.jsx)(n.td,{children:"Carried in the default config file for reference; not currently consumed by the SPF library (cache lifetime is determined by DNS record TTL)"})]}),(0,i.jsxs)(n.tr,{children:[(0,i.jsx)(n.td,{children:(0,i.jsx)(n.code,{children:"max_dns_nesting"})}),(0,i.jsx)(n.td,{children:"10"}),(0,i.jsx)(n.td,{children:"Maximum number of recursive DNS subrequests (include chain length)"})]}),(0,i.jsxs)(n.tr,{children:[(0,i.jsx)(n.td,{children:(0,i.jsx)(n.code,{children:"max_dns_requests"})}),(0,i.jsx)(n.td,{children:"30"}),(0,i.jsx)(n.td,{children:"Maximum count of DNS requests per record"})]}),(0,i.jsxs)(n.tr,{children:[(0,i.jsx)(n.td,{children:(0,i.jsx)(n.code,{children:"min_cache_ttl"})}),(0,i.jsx)(n.td,{children:"5min"}),(0,i.jsx)(n.td,{children:"Minimum TTL enforced for all elements in SPF records"})]}),(0,i.jsxs)(n.tr,{children:[(0,i.jsx)(n.td,{children:(0,i.jsx)(n.code,{children:"disable_ipv6"})}),(0,i.jsx)(n.td,{children:"false"}),(0,i.jsx)(n.td,{children:"Disable all IPv6 lookups"})]}),(0,i.jsxs)(n.tr,{children:[(0,i.jsx)(n.td,{children:(0,i.jsx)(n.code,{children:"whitelist"})}),(0,i.jsx)(n.td,{children:"nil"}),(0,i.jsx)(n.td,{children:"Map of IP addresses to whitelist from checks"})]}),(0,i.jsxs)(n.tr,{children:[(0,i.jsx)(n.td,{children:(0,i.jsx)(n.code,{children:"external_relay"})}),(0,i.jsx)(n.td,{children:"nil"}),(0,i.jsxs)(n.td,{children:["Radix map of trusted relay IP addresses. When a received header's ",(0,i.jsx)(n.code,{children:"by"})," IP matches an entry, the next hop's IP from the received chain is used as the SPF check 
1source instead of the connection IP. Useful when the MTA sits behind a fixed trusted relay and the external_relay module is not applicable."]})]})]})]}),"\n",(0,i.jsx)(n.h2,{id:"symbols",children:"Symbols"}),"\n",(0,i.jsx)(n.p,{children:"The module produces the following symbols:"}),"\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\n\n\n\n\n\n",(0,i.jsxs)(n.table,{children:[(0,i.jsx)(n.thead,{children:(0,i.jsxs)(n.tr,{children:[(0,i.jsx)(n.th,{children:"Symbol"}),(0,i.jsx)(n.th,{children:"Description"})]})}),(0,i.jsxs)(n.tbody,{children:[(0,i.jsxs)(n.tr,{children:[(0,i.jsx)(n.td,{children:(0,i.jsx)(n.code,{children:"R_SPF_ALLOW"})}),(0,i.jsx)(n.td,{children:"SPF check passed"})]}),(0,i.jsxs)(n.tr,{children:[(0,i.jsx)(n.td,{children:(0,i.jsx)(n.code,{children:"R_SPF_FAIL"})}),(0,i.jsx)(n.td,{children:"SPF check failed (hard fail)"})]}),(0,i.jsxs)(n.tr,{children:[(0,i.jsx)(n.td,{children:(0,i.jsx)(n.code,{children:"R_SPF_SOFTFAIL"})}),(0,i.jsx)(n.td,{children:"SPF check soft failed"})]}),(0,i.jsxs)(n.tr,{children:[(0,i.jsx)(n.td,{children:(0,i.jsx)(n.code,{children:"R_SPF_NEUTRAL"})}),(0,i.jsx)(n.td,{children:"SPF neutral result"})]}),(0,i.jsxs)(n.tr,{children:[(0,i.jsx)(n.td,{children:(0,i.jsx)(n.code,{children:"R_SPF_DNSFAIL"})}),(0,i.jsx)(n.td,{children:"DNS failure during SPF check"})]}),(0,i.jsxs)(n.tr,{children:[(0,i.jsx)(n.td,{children:(0,i.jsx)(n.code,{children:"R_SPF_PERMFAIL"})}),(0,i.jsx)(n.td,{children:"Permanent SPF failure (e.g., invalid record)"})]}),(0,i.jsxs)(n.tr,{children:[(0,i.jsx)(n.td,{children:(0,i.jsx)(n.code,{children:"R_SPF_NA"})}),(0,i.jsx)(n.td,{children:"No SPF record found"})]}),(0,i.jsxs)(n.tr,{children:[(0,i.jsx)(n.td,{children:(0,i.jsx)(n.code,{children:"R_SPF_PLUSALL"})}),(0,i.jsx)(n.td,{children:"SPF record contains +all (accepts all)"})]})]})]}),"\n",(0,i.jsx)(n.h2,{id:"example-configuration",children:"Example configuration"}),"\n",(0,i.jsx)(n.pre,{children:(0,i.jsx)(n.code,{className:"language-hcl",children:'# local.d/spf.conf\n\nspf_cache_size = 2048; # cache up to 2048 of the most recent SPF records\nmax_dns_nesting = 10; # maximum number of recursive DNS subrequests\nmax_dns_requests = 30; # maximum count of DNS requests per record\nmin_cache_ttl = 5min; # minimum TTL enforced for all elements in SPF records\ndisable_ipv6 = false; # disable all IPv6 lookups\nwhitelist = "/path/to/some/file"; # whitelist IPs from checks\n# external_relay = ["192.168.1.1"]; # use IP from received headers when connection comes via this relay\n'})}),"\n",(0,i.jsx)(n.h2,{id:"using-spf-with-forwarding",children:"Using SPF with forwarding"}),"\n",(0,i.jsxs)(n.p,{children:["If your MTA is placed behind some trusted forwarder you can still check SPF policies for the originating domains and IP addresses. The recommended approach is to use the dedicated ",(0,i.jsx)(n.a,{href:"/modules/external_relay",children:"external relay"})," module, which provides richer functionality. Alternatively, the ",(0,i.jsx)(n.code,{children:"external_relay"})," option in the SPF plugin itself is fully functional: configure it as a list of trusted relay IPs and the SPF check will use the preceding hop's IP from the received headers instead of the connection IP."]})]})}function h(e={}){const{wrapper:n}={...(0,d.R)(),...e.components};return n?(0,i.jsx)(n,{...e,children:(0,i.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.