作者: william
rspamd設定灰名單(greylist)
原本我建議大家不要用灰名單, 原因是:
1. 等很久,
2. 系統自動發信,無法通過灰名單測試, 但是該信件又是極其重要
因此建議停用灰名單功能.
但近年來廣告信,釣魚信多到影響資通安全, 我們就必須要開啟灰名單功能, 策略如下:
1.若是重要信件,先加入灰名單裡面的白名單,
2.若通過灰名單測試後, 可以設定成長時間不用再通過灰名單測試
以下是rspamd開啟灰名單功能
- 修改 local.d/greylist.conf
enabled = true;
expire = 365d; # 1 day by default
timeout = 5min; # 5 minutes by default
- 修改 override.d/actions.conf
# 若郵件高於4分, 就觸發灰名單功能
greylist = 4;# Apply greylisting when reaching this score (will emit `soft reject action`)
- 灰名單白名單功能,
將不需要觸發灰名單的網域加入到 local.d/greylist-whitelist-domains.inc
android kotlin 呼叫(發起)email app
好多種版本, 終於找到可以用的
- 第一種寫法(比較適合寫慣java的老師傅)
val email_intent = Intent(Intent.ACTION_SENDTO, Uri.parse("mailto:"));
email_intent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION)
email_intent.putExtra(Intent.EXTRA_EMAIL, arrayOf("your@email.com"))
email_intent.putExtra(Intent.EXTRA_SUBJECT, "問題回報");
email_intent.putExtra(Intent.EXTRA_TEXT,"");
try {
startActivity(Intent.createChooser(email_intent, "請選擇郵件軟體"))
}catch (e:ActivityNotFoundException){
Toast.makeText(myactivity, "請確認並設定好郵件收發軟體", Toast.LENGTH_LONG).show()
}
- 第二種寫法
val email_intent = Intent(Intent.ACTION_SENDTO, Uri.parse("mailto:")).apply {
addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION)
putExtra(Intent.EXTRA_EMAIL, arrayOf("your@email.com"))
putExtra(Intent.EXTRA_SUBJECT, "問題回報")
putExtra(Intent.EXTRA_TEXT, "")
}
try {
startActivity(Intent.createChooser(email_intent, "請選擇郵件軟體"))
} catch ( ex: ActivityNotFoundException) {
Toast.makeText(myactivity, "請確認並設定好郵件收發軟體", Toast.LENGTH_LONG).show()
}
使用restic做離線備份, 充滿儀式感,老闆也開心
前陣子發現restic備份的好處, 尤其拿來當離線備份.
IT同事進行離線備份時, 有意無意被老闆路過, 看到滿滿備份畫面咻咻跑來跑去, 充滿了儀式感.
老闆開心, IT同仁也有成就感.

restic指令備份, 不夠自動化, 為了讓IT同事做少少的工作, 又讓IT同事與其他路過的同事覺得好專業, 因此寫了簡單的restic backup script , 可以協助掛載來源目錄, 掛載後,進行restic備份.


檔案請到這裡下載, 下載後請看readme.md檔案
centos 安裝dkim並且自動產生相關文件
先前寫了一篇centos7安裝opendkim+postfix 這只是單一網域, 若要多個網域,實在是很麻煩
google爬文爬到一篇文章,有神人寫了自動產生相關文件的shell script , 我稍微修改一下, 就能很方便產生相關文件.
- 安裝dkim套件
#centos 7
yum install opendkim
#centos 8 , rocky linux 8
yum install opendkim opendkim-tools
- 下載 scripts,
下載後, 修改裡面的網域, 執行後會產生相關檔案
https://kafeiou.pw/wp-content/uploads/2022/06/getOpenDKIM.zip
- 修改 opendkim.conf
把Mode 改成 sv

postfix寄信認證改用dovecot
一直以來我都讓postfix使用 sasl 方式處裡寄信認證, 但是連結到多網域主控伺服器的時候, 就會出錯, 很麻煩.
經過測試 dovecot 可以使用多組 userdb , 與passdb , 達到一個mail server 支援多個ldap網域主控.
當然也能省下一個sasl的service
- 修改dovecort的 conf.d/10-master.conf
service auth {
...
unix_listener /var/spool/postfix/private/auth {
mode = 0660
# Assuming the default Postfix user and group
user = postfix
group = postfix
}
...
}
#以下設定為了相容outlook系統
auth_mechanisms = plain login
- 修改postfix的main.cf
smtpd_sasl_type = dovecot
smtpd_sasl_path = private/auth
# On Debian Wheezy path must be relative and queue_directory defined
#queue_directory = /var/spool/postfix
# and the common settings to enable SASL:
smtpd_sasl_auth_enable = yes
- 修改postfix的master.cf
submission inet n - n - - smtpd
-o smtpd_tls_security_level=encrypt
-o smtpd_sasl_auth_enable=yes
-o smtpd_sasl_type=dovecot
-o smtpd_sasl_path=private/auth
-o smtpd_sasl_security_options=noanonymous
-o smtpd_sasl_local_domain=$myhostname
-o smtpd_client_restrictions=permit_sasl_authenticated,reject
-o smtpd_sender_login_maps=hash:/etc/postfix/virtual
-o smtpd_sender_restrictions=reject_sender_login_mismatch
...
參考:
https://doc.dovecot.org/configuration_manual/howto/postfix_and_dovecot_sasl/
esxi 6.7踩雷, NFS 不支援delayed ack導致連線異常緩慢
移除windows 10或以後版本,路徑檔案超過260個字元
這真是很令人頭疼的問題, 預設是不能超過260個字元, 微軟說windows 10 1607版本後面,可以自行調整開啟長檔名的功能
從 Windows 10 1607 版開始,已從一般 Win32 檔案和目錄函式中移除MAX_PATH限制。 不過,您必須加入宣告新的行為
- 個人主機
修改reg
Windows Registry Editor Version 5.00
[HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Control\FileSystem]
"LongPathsEnabled"=dword:00000001
或是改本機原則
Computer Configuration > Administrative Templates > System > Filesystem > Enable Win32 long paths
- 公司主機(網域主控群組原則)
- AD: windows 2012R2或之前的才需要這樣做
- 安裝最新版windows 10 管理範本
https://www.microsoft.com/en-us/download/103124 - 將windows 10管理範本複製到目前網域的群組原則
複製 C:\Program Files (x86)\Microsoft Group Policy\Windows 10 and Windows Server 2016\PolicyDefinitions
到
SYSVOL\domain\Policies\PolicyDefinitions - 重新執行群組原則設定, 就能看到 Enable win32 long paths

android kotlin coroutines
import kotlinx.coroutines.*
fun main() {
repeat(3) {
GlobalScope.launch {
println("Hi from ${Thread.currentThread()}")
}
}
}
- 非同步
import kotlinx.coroutines.*
import java.time.LocalDateTime
import java.time.format.DateTimeFormatter
val formatter = DateTimeFormatter.ISO_LOCAL_TIME
val time = { formatter.format(LocalDateTime.now()) }
suspend fun getValue(): Double {
println("entering getValue() at ${time()}")
delay(3000)
println("leaving getValue() at ${time()}")
return Math.random()
}
fun main() {
runBlocking {
val num1 = getValue()
val num2 = getValue()
println("result of num1 + num2 is ${num1 + num2}")
}
}
同步
import kotlinx.coroutines.*
import java.time.LocalDateTime
import java.time.format.DateTimeFormatter
val formatter = DateTimeFormatter.ISO_LOCAL_TIME
val time = { formatter.format(LocalDateTime.now()) }
suspend fun getValue(): Double {
println("entering getValue() at ${time()}")
delay(3000)
println("leaving getValue() at ${time()}")
return Math.random()
}
fun main() {
runBlocking {
val num1 = async { getValue() }
val num2 = async { getValue() }
println("result of num1 + num2 is ${num1.await() + num2.await()}")
}
}
job
val job: Job = GlobalScope.launch(Dispatchers.Main) {
// launch coroutine in the main thread
for (i in 10 downTo 1) { // countdown from 10 to 1
textView.text = "count down $i ..." // update text
delay(1000) // wait half a second
}
textView.text = "Done!"
}
job.cancel()
android kotlin viewBinding 新做法
寫android總是寫不好, 之前取得view要使用findViewByI的方式, 過了一段時間回頭看, 現在又改了改成使用viewBinding 說是比較快…
- gradle(module)
buildFeatures {
viewBinding = true
}
- main activity
class MainActivity : AppCompatActivity() {
lateinit var binding: ActivityMainBinding
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
binding = ActivityMainBinding.inflate(layoutInflater)
setContentView(binding.root)
}
}
- 使用方式變簡單了
// 舊版
val myButton: Button = findViewById(R.id.my_button)
myButton.text = "A button"
// 新版
val myButton: Button = binding.myButton
myButton.text = "A button"
// Best way with view binding and no extra variable
binding.myButton.text = "A button"
