Hi I’m Shiun

Backend, DevOps, Cloud and Cats!!!

以真實世界寄信來比喻,理解電子郵件寄送流程

因為我最近在開發寄信系統,因此理解電子郵件寄送的流程和原理是很重要的,為了方便理解,所以我會用真實世界中我們去郵局寄信來比喻電子郵件的寄送流程,這麼做是為了幫助理解,所以比喻那部分很難做到 100% 完全和技術細節對齊 用真實世界在郵局寄信,理解電子郵件寄送的流程 圖片取自: 維基百科 為了更好地理解電子郵件的寄送過程,我們可以把它比作郵局寄信的過程。假設 Alice 給 Bob 寫了一封感謝信,然後她將信件帶到郵局處理寄信手續。接下來,我們來看看具體過程: 創建信件 郵局寄信: Alice 寫好感謝信,裝進信封,寫上寄件人和收件人的地址,貼上郵票。 電子郵件: 你在郵件客戶端 (例如: Outlook、Gmail) 或透過 API 建立一封郵件,內容包含寄件人 (例如: alice@example.tw) 、收件人 (例如: bob@demodomain.tw) 、主題、內文及其他可能的附件。 信件寄送 郵局寄信: Alice 把信帶到郵局,然後找郵局的櫃台人員。 電子郵件: 當你點擊「寄送」後,郵件客戶端會將這封郵件交給寄件人的郵件伺服器,稱為 SMTP 伺服器 (Simple Mail Transfer Protocol) 。 SMTP 伺服器處理 郵局寄信: 郵局的櫃台人員會檢查地址是否正確,然後進行分類。 電子郵件: 寄件人的 SMTP 伺服器會驗證寄件人的身份,檢查信件格式是否正確,並根據收件人的域名 (例如: demodomain.tw) 查找相應的 MX 記錄 (Mail Exchange) 來確定收件人的郵件伺服器位置。 像如果對方沒有設定 MX Record,寄信過去就會出現以下 ERROR,找不到對應的 MX Record DNS 查詢 郵局寄信: 郵局櫃台人員會根據地址查找對應郵遞區號。 電子郵件: 寄件人的 SMTP 伺服器會透過 DNS (Domain Name System) 查詢收件人域名的 MX 記錄,以獲取負責接收郵件的伺服器的 IP 位址。 信件傳輸...

August 8, 2024 · 1 min

從 AWS SES 轉寄信件無法正確顯示內嵌圖片談起:MIME 內嵌圖片原理與實踐

我遇到了什麼問題 最近我用 SES, S3, Lambda 開發了轉寄信件的功能,簡單介紹一下這功能: 假設我就職於公司的開發部門,我們對外有一個信箱是 dev@example.com 當客戶遇到軟體開發上的問題時寄信到 dev@example.com,開發部門的所有同仁就會在自己的信箱收到此客戶寄來的電子郵件,重點是開發部門的同仁們都可以用自己的帳號回覆該客戶 而開發好這功能後,我遇到一個問題 — 轉寄出去的信件沒辦法正確顯示內嵌圖片 關於轉寄信件的程式碼我放在 GitHub 上囉 (連結),之後有時間會寫一篇 Forward Email 的完整教學,或是也可以關注我的 Notion,我每天都會寫筆記記錄自己的學習過程 讓我們直接看例子 首先,我登入私人帳號模擬我是客戶,寄信給 test@aws-educate.tw,下圖是當時寄出去的內容: 寄給 test@aws-educate.tw 後,SES 會收到信,然後根據我配置的 Receipt rule,原始郵件檔案會被儲存至我指定的 S3 Bucket 延續 用 SES, S3, Lambda 實現轉寄信件功能 ,當我嘗試在轉寄出去的信件中內嵌圖片,最後收到轉寄來的信,都會出現下圖的現象:圖片沒辦法內嵌在裡面,倒是跑去附件了 寫文章時,已經把原本轉寄過來的信件刪了,所以下圖信件主旨跟前一張圖片不一樣不要介意,下圖信件已經詮釋我想表達的現象了 XD 我起初嘗試的解法 後來下面這篇 Stack Overflow,裡面有人提到 Gmail 還不支援顯示 base64 編碼的圖片 (有待確認,希望有人可以告訴我正確答案) As of January 2020, Gmail still does not support base64 encoded images. Source: Add embedded image in emails in AWS SES service...

August 6, 2024 · 2 min

在 Next.js 音樂應用中使用動態 Preload 技術提升前端效能降低延遲

程式碼在這邊的 feature/preload 分支: https://github.com/sh1un/Nextjs-Musive-app 此專案是一個 Next.js 專案,原作者為 Ansh Rathod,我已經過作者本人授權使用,因此 Fork 過來稍微改了一下。 我本身不是一名專精於前端技術的開發者,所以我所修改的 Code 都是由 ChatGPT-4 產生的。我今天這樣做的主要目的是想實驗 preload 是否能做到效能優化,以此來做一個簡單的 PoC。 補充一下,這篇文章的內容本來是要放在 「2024 AWS Educate 陪跑計畫的獎勵課程 - 雲端串流挑戰:復刻 Spotify 的技術旅程」中教學,此工作坊旨在教學如何利用 CloudFront 優化速度與降低延遲,但礙於當天工作坊的內容太滿已經塞不下了,所以當天工作坊就沒有講到 Preload,如果看到這篇文章,想要學學 CloudFront 歡迎參觀我們當天的教材 (連結) 什麼是 Preload? Preload 是一種網頁性能優化技術,讓瀏覽器在頁面加載時預先加載指定的資源,這樣在使用這些資源時可以更快地顯示或播放。這可以減少等待時間,提升用戶體驗。 你可以想成:原本你是要“按下去播放按鈕”才會開始下載音樂,現在我們提前幫你下載,你之後“按下去播放按鈕”就會立即播放。 舉例 如果你在網頁上有一段影片或音樂,你可以用 preload 告訴瀏覽器提前下載這些文件,這樣當用戶點擊播放按鈕時,影片或音樂就會立即播放,而不是先等待下載。 基本用法: 在 HTML 中,你可以在 <link> 標籤中使用 rel="preload" 來預加載資源。例如: <link rel="preload" href="path/to/your/file.mp3" as="audio"> 這樣,瀏覽器會在頁面加載時預先下載 file.mp3,提高用戶播放音樂的速度。 動態 Preload 的實現思路 每個用戶的歌單都不一樣,所以我們當然不希望把 preload 的 href 寫死成一個 URL。 解決方案 我們可以通過以下幾個步驟來實現動態的 preload: API 獲取歌單: 伺服器端提供一個 API,根據用戶的請求返回該用戶的歌單。這個 API 返回一個 JSON 結構,其中包含了音樂檔案的 URL 列表。 JavaScript 動態生成 Preload 標籤: 使用 JavaScript 在頁面加載後動態地從 API 獲取歌單,並為每個音樂文件創建 preload 標籤,將其添加到頁面的 <head> 中。 具體實現 注意⚠️ 我的寫法並非添加 preload 到頁面的 <head>,而是直接用 React 和 JS 本身提供的內建物件來達到同樣效果,詳見本段說明。...

July 21, 2024 · 4 min

2024 伊雲谷實習計畫 - 雲端工程師實習心得

大家好,我是 Shiun,今天想和大家分享我在 eCloudValley MSP 部門擔任雲端工程師實習生的經歷。這段實習讓我學到了很多實用的雲端技術,同時也在工作中遇到了許多有趣的挑戰。 實習工作內容 在 eCloudValley 的實習期間,我主要負責以下幾項工作: 學習使用公有雲,包括 AWS 和 Azure。 開發公司內部的 GenAI 應用。 與同期且同部門實習生共同開發專案。 定期與 Mentor 開會。 參與最終展演。 撰寫系統文件。 實習期間大事紀 專案大改方向 在 eCloudValley 實習期間,我們的專案經歷了一次重大轉變。起初,我們的任務是開發一個 AI Bot 開單助理,目的是幫助客戶在雲端遇到問題時能夠迅速獲得支援。這個專案的初步構想是: 客戶向 AI 助理求助,並向 AI 助理提供必要資訊,例如: EC2 SG Inbound Rule, 健康檢查狀態… 等等 如果客戶提供的資訊不夠明確,AI 助理要明確地告知客戶還需提供哪些資訊。 AI 助理彙總客戶問題,轉化為技術人員易於理解的語言。 將資訊轉化後,開 ticket 到開單系統。 然而,在實作過程中,我們發現這個 AI 助理的效果不如預期,且後續優化存在技術瓶頸。客戶問題過於多樣化、且問題幾乎都很具情境,不是那種有標準解答或是標準 SOP 就能解決的問題,所以 AI 助理難以處理,導致準確率低,最終還是需要人工介入,反而增加了工作量。 因此,我們在 4 月底決定將專案轉變為一個「會議錄影機器人」。這個機器人會被邀請到 LINE 群組中,默默記錄每一條訊息以及圖片 (圖片透過 Claude 3 Sonnet 取得 Caption)。TAM 只需在群組中輸入特殊指令或貼圖即可控制錄影,最終在前端頁面查看記錄並由 LLM 總結,創建 Ticket 到 MSP 部門的 Ticket System。...

July 20, 2024 · 1 min

如何使用 Lambda 處理 AWS Cognito User 首次登入被系統要求強制變更密碼

情境描述 上圖顯示的是我剛在 Cognito User Pool 中新增了一個 user,可以注意到箭頭處顯示 Force change password。 當這個 user 嘗試首次登入時,他們會遇到這樣的情況: { "message": "New password required", "challengeName": "NEW_PASSWORD_REQUIRED", "session": "AYABeAsYJsR3yEr0iJssKPPUPEgAHQABAAdTZXJ2aWNlABBDb2duaXRvVXNlclBvb2xzAAEAB2F3cy1rbXMAS2Fybjphd3M6a21zOnVzLXdlc3QtMjowMTU3MzY3MjcxOTg6a2V5LzI5OTFhNGE5LTM5YTAtNDQ0Mi04MWU4LWRkYjY4NTllMTg2MQC4AQIBAHhPj7k9zU4nGXUQUvM0Ccwk42DS-fm3vKmH75ktTrktNQG1gnjl6HkUVUYN1J_HPow6AAAAfjB8BgkqhkiG9w0BBwagbzBtAgEAMGgGCSqGSIb3DQEHATAeBglghkgBZQMEAS4wEQQMulTha32s34j2CmQWAgEQgDtog8CDFh2e-4YyjM2kB_MXheMgmrdY_IF3aN9TImZXddMBj7djEAPPduLZnG3ddBLYQa8x3T3WPKUkvwIAAAAADAAAEAAAAAAAAAAAAAAAAADCbdmpLPo0E4QkWLlyH8ov_____wAAAAEAAAAAAAAAAAAAAAEAAAC1oMtgshmuUU4fk36WHKBzPgJEoE1MmL0PFyhR9lRcimImOIObhhxvC1fwiYylgbYx0Gu0i1cp5Le8AvrAnUGEJjZp54TMPP4N-JCT3qSrHeq_Kat_2CuECVSQqkc1qH4z9FVOTvAnos4FrDSn2W6KvFfLo8YQh2LJxM1h3GdIeyYqj7Ipfk6PZKGYmV5P741rRMNcuYBtvE8Hq9gVqMbEPG-c5MppY_q9JoG9TyQRN7rVGlZf62_WtTqST2F3-DZPoXTMTyY", "challengeParameters": { "USER_ID_FOR_SRP": "shiun", "requiredAttributes": "[]", "userAttributes": "{\"email\":\"xxxxx@gmail.com\"}" } } Cognito 回傳了一個 NEW_PASSWORD_REQUIRED 的 challenge,同時給了我們一個 session token。這就是我們需要處理的 case。 解決方案 要解決這個問題,我們需要提供一個 change-password 的 API endpoint,讓 user 可以順利更改密碼。整個 flow 大致如下: User 首次登入 Cognito 回傳 NEW_PASSWORD_REQUIRED challenge 和 session token 前端帶著 session token 呼叫我們的 change-password API 密碼更改成功,user 順利登入系統 以下是一個處理這種情況的 Lambda function 範例:...

July 19, 2024 · 2 min