diff --git a/.env.template b/.env.template
index 60b5b73bbf3840016f451029fa443795c9e6a18c..1e5ff101e21863b06f3f1144d7313764c86f762c 100644
--- a/.env.template
+++ b/.env.template
@@ -367,6 +367,9 @@
 ## but might need to be changed in case it trips some anti-spam filters
 # HELO_NAME=
 
+## Embed images as email attachments
+# SMTP_EMBED_IMAGES=false
+
 ## SMTP debugging
 ## When set to true this will output very detailed SMTP messages.
 ## WARNING: This could contain sensitive information like passwords and usernames! Only enable this during troubleshooting!
diff --git a/src/config.rs b/src/config.rs
index 3a2cf958b0bc2b8f643087ac4d7e80b52fb1dad2..4cac70eb917836ab48e443b184de96a4368c5d43 100644
--- a/src/config.rs
+++ b/src/config.rs
@@ -602,6 +602,10 @@ make_config! {
         smtp_timeout:                  u64,    true,   def,     15;
         /// Server name sent during HELO |> By default this value should be is on the machine's hostname, but might need to be changed in case it trips some anti-spam filters
         helo_name:                     String, true,   option;
+        /// Embed images as email attachments.
+        smtp_embed_images:             bool, true, def, true;
+        /// Internal
+        _smtp_img_src:                 String, false, gen, |c| generate_smtp_img_src(c.smtp_embed_images, &c.domain);
         /// Enable SMTP debugging (Know the risks!) |> DANGEROUS: Enabling this will output very detailed SMTP messages. This could contain sensitive information like passwords and usernames! Only enable this during troubleshooting!
         smtp_debug:                    bool,   false,  def,     false;
         /// Accept Invalid Certs (Know the risks!) |> DANGEROUS: Allow invalid certificates. This option introduces significant vulnerabilities to man-in-the-middle attacks!
@@ -759,6 +763,14 @@ fn extract_url_path(url: &str) -> String {
     }
 }
 
+fn generate_smtp_img_src(embed_images: bool, domain: &str) -> String {
+    if embed_images {
+        "cid:".to_string()
+    } else {
+        format!("{}/vw_static/", domain)
+    }
+}
+
 /// Generate the correct URL for the icon service.
 /// This will be used within icons.rs to call the external icon service.
 fn generate_icon_service_url(icon_service: &str) -> String {
diff --git a/src/mail.rs b/src/mail.rs
index 5cc126588d3c6c8607c9b80bf73b0856d271a54a..e613da6f3880773b096bacd5aef76f4706d41243 100644
--- a/src/mail.rs
+++ b/src/mail.rs
@@ -4,7 +4,7 @@ use chrono::NaiveDateTime;
 use percent_encoding::{percent_encode, NON_ALPHANUMERIC};
 
 use lettre::{
-    message::{Mailbox, Message, MultiPart},
+    message::{Attachment, Body, Mailbox, Message, MultiPart, SinglePart},
     transport::smtp::authentication::{Credentials, Mechanism as SmtpAuthMechanism},
     transport::smtp::client::{Tls, TlsParameters},
     transport::smtp::extension::ClientId,
@@ -117,7 +117,14 @@ pub async fn send_password_hint(address: &str, hint: Option<String>) -> EmptyRes
         "email/pw_hint_none"
     };
 
-    let (subject, body_html, body_text) = get_text(template_name, json!({ "hint": hint, "url": CONFIG.domain() }))?;
+    let (subject, body_html, body_text) = get_text(
+        template_name,
+        json!({
+            "url": CONFIG.domain(),
+            "img_src": CONFIG._smtp_img_src(),
+            "hint": hint,
+        }),
+    )?;
 
     send_email(address, &subject, body_html, body_text).await
 }
@@ -130,6 +137,7 @@ pub async fn send_delete_account(address: &str, uuid: &str) -> EmptyResult {
         "email/delete_account",
         json!({
             "url": CONFIG.domain(),
+            "img_src": CONFIG._smtp_img_src(),
             "user_id": uuid,
             "email": percent_encode(address.as_bytes(), NON_ALPHANUMERIC).to_string(),
             "token": delete_token,
@@ -147,6 +155,7 @@ pub async fn send_verify_email(address: &str, uuid: &str) -> EmptyResult {
         "email/verify_email",
         json!({
             "url": CONFIG.domain(),
+            "img_src": CONFIG._smtp_img_src(),
             "user_id": uuid,
             "email": percent_encode(address.as_bytes(), NON_ALPHANUMERIC).to_string(),
             "token": verify_email_token,
@@ -161,6 +170,7 @@ pub async fn send_welcome(address: &str) -> EmptyResult {
         "email/welcome",
         json!({
             "url": CONFIG.domain(),
+            "img_src": CONFIG._smtp_img_src(),
         }),
     )?;
 
@@ -175,6 +185,7 @@ pub async fn send_welcome_must_verify(address: &str, uuid: &str) -> EmptyResult
         "email/welcome_must_verify",
         json!({
             "url": CONFIG.domain(),
+            "img_src": CONFIG._smtp_img_src(),
             "user_id": uuid,
             "token": verify_email_token,
         }),
@@ -188,6 +199,7 @@ pub async fn send_2fa_removed_from_org(address: &str, org_name: &str) -> EmptyRe
         "email/send_2fa_removed_from_org",
         json!({
             "url": CONFIG.domain(),
+            "img_src": CONFIG._smtp_img_src(),
             "org_name": org_name,
         }),
     )?;
@@ -200,6 +212,7 @@ pub async fn send_single_org_removed_from_org(address: &str, org_name: &str) ->
         "email/send_single_org_removed_from_org",
         json!({
             "url": CONFIG.domain(),
+            "img_src": CONFIG._smtp_img_src(),
             "org_name": org_name,
         }),
     )?;
@@ -228,6 +241,7 @@ pub async fn send_invite(
         "email/send_org_invite",
         json!({
             "url": CONFIG.domain(),
+            "img_src": CONFIG._smtp_img_src(),
             "org_id": org_id.as_deref().unwrap_or("_"),
             "org_user_id": org_user_id.as_deref().unwrap_or("_"),
             "email": percent_encode(address.as_bytes(), NON_ALPHANUMERIC).to_string(),
@@ -260,6 +274,7 @@ pub async fn send_emergency_access_invite(
         "email/send_emergency_access_invite",
         json!({
             "url": CONFIG.domain(),
+            "img_src": CONFIG._smtp_img_src(),
             "emer_id": emer_id.unwrap_or_else(|| "_".to_string()),
             "email": percent_encode(address.as_bytes(), NON_ALPHANUMERIC).to_string(),
             "grantor_name": grantor_name,
@@ -275,6 +290,7 @@ pub async fn send_emergency_access_invite_accepted(address: &str, grantee_email:
         "email/emergency_access_invite_accepted",
         json!({
             "url": CONFIG.domain(),
+            "img_src": CONFIG._smtp_img_src(),
             "grantee_email": grantee_email,
         }),
     )?;
@@ -287,6 +303,7 @@ pub async fn send_emergency_access_invite_confirmed(address: &str, grantor_name:
         "email/emergency_access_invite_confirmed",
         json!({
             "url": CONFIG.domain(),
+            "img_src": CONFIG._smtp_img_src(),
             "grantor_name": grantor_name,
         }),
     )?;
@@ -299,6 +316,7 @@ pub async fn send_emergency_access_recovery_approved(address: &str, grantor_name
         "email/emergency_access_recovery_approved",
         json!({
             "url": CONFIG.domain(),
+            "img_src": CONFIG._smtp_img_src(),
             "grantor_name": grantor_name,
         }),
     )?;
@@ -316,6 +334,7 @@ pub async fn send_emergency_access_recovery_initiated(
         "email/emergency_access_recovery_initiated",
         json!({
             "url": CONFIG.domain(),
+            "img_src": CONFIG._smtp_img_src(),
             "grantee_name": grantee_name,
             "atype": atype,
             "wait_time_days": wait_time_days,
@@ -335,6 +354,7 @@ pub async fn send_emergency_access_recovery_reminder(
         "email/emergency_access_recovery_reminder",
         json!({
             "url": CONFIG.domain(),
+            "img_src": CONFIG._smtp_img_src(),
             "grantee_name": grantee_name,
             "atype": atype,
             "days_left": days_left,
@@ -349,6 +369,7 @@ pub async fn send_emergency_access_recovery_rejected(address: &str, grantor_name
         "email/emergency_access_recovery_rejected",
         json!({
             "url": CONFIG.domain(),
+            "img_src": CONFIG._smtp_img_src(),
             "grantor_name": grantor_name,
         }),
     )?;
@@ -361,6 +382,7 @@ pub async fn send_emergency_access_recovery_timed_out(address: &str, grantee_nam
         "email/emergency_access_recovery_timed_out",
         json!({
             "url": CONFIG.domain(),
+            "img_src": CONFIG._smtp_img_src(),
             "grantee_name": grantee_name,
             "atype": atype,
         }),
@@ -374,6 +396,7 @@ pub async fn send_invite_accepted(new_user_email: &str, address: &str, org_name:
         "email/invite_accepted",
         json!({
             "url": CONFIG.domain(),
+            "img_src": CONFIG._smtp_img_src(),
             "email": new_user_email,
             "org_name": org_name,
         }),
@@ -387,6 +410,7 @@ pub async fn send_invite_confirmed(address: &str, org_name: &str) -> EmptyResult
         "email/invite_confirmed",
         json!({
             "url": CONFIG.domain(),
+            "img_src": CONFIG._smtp_img_src(),
             "org_name": org_name,
         }),
     )?;
@@ -403,6 +427,7 @@ pub async fn send_new_device_logged_in(address: &str, ip: &str, dt: &NaiveDateTi
         "email/new_device_logged_in",
         json!({
             "url": CONFIG.domain(),
+            "img_src": CONFIG._smtp_img_src(),
             "ip": ip,
             "device": device,
             "datetime": crate::util::format_naive_datetime_local(dt, fmt),
@@ -421,6 +446,7 @@ pub async fn send_incomplete_2fa_login(address: &str, ip: &str, dt: &NaiveDateTi
         "email/incomplete_2fa_login",
         json!({
             "url": CONFIG.domain(),
+            "img_src": CONFIG._smtp_img_src(),
             "ip": ip,
             "device": device,
             "datetime": crate::util::format_naive_datetime_local(dt, fmt),
@@ -436,6 +462,7 @@ pub async fn send_token(address: &str, token: &str) -> EmptyResult {
         "email/twofactor_email",
         json!({
             "url": CONFIG.domain(),
+            "img_src": CONFIG._smtp_img_src(),
             "token": token,
         }),
     )?;
@@ -448,6 +475,7 @@ pub async fn send_change_email(address: &str, token: &str) -> EmptyResult {
         "email/change_email",
         json!({
             "url": CONFIG.domain(),
+            "img_src": CONFIG._smtp_img_src(),
             "token": token,
         }),
     )?;
@@ -460,6 +488,7 @@ pub async fn send_test(address: &str) -> EmptyResult {
         "email/smtp_test",
         json!({
             "url": CONFIG.domain(),
+            "img_src": CONFIG._smtp_img_src(),
         }),
     )?;
 
@@ -467,13 +496,33 @@ pub async fn send_test(address: &str) -> EmptyResult {
 }
 
 async fn send_email(address: &str, subject: &str, body_html: String, body_text: String) -> EmptyResult {
+    let logo_gray_body = Body::new(include_bytes!("static/images/logo-gray.png").to_vec());
+    let mail_github_body = Body::new(include_bytes!("static/images/mail-github.png").to_vec());
     let smtp_from = &CONFIG.smtp_from();
+
+    let body = if CONFIG.smtp_embed_images() {
+        MultiPart::alternative().singlepart(SinglePart::plain(body_text)).multipart(
+            MultiPart::related()
+                .singlepart(SinglePart::html(body_html))
+                .singlepart(
+                    Attachment::new_inline(String::from("logo-gray.png"))
+                        .body(logo_gray_body, "image/png".parse().unwrap()),
+                )
+                .singlepart(
+                    Attachment::new_inline(String::from("mail-github.png"))
+                        .body(mail_github_body, "image/png".parse().unwrap()),
+                ),
+        )
+    } else {
+        MultiPart::alternative_plain_html(body_text, body_html)
+    };
+
     let email = Message::builder()
         .message_id(Some(format!("<{}@{}>", crate::util::get_uuid(), smtp_from.split('@').collect::<Vec<&str>>()[1])))
         .to(Mailbox::new(None, Address::from_str(address)?))
         .from(Mailbox::new(Some(CONFIG.smtp_from_name()), Address::from_str(smtp_from)?))
         .subject(subject)
-        .multipart(MultiPart::alternative_plain_html(body_text, body_html))?;
+        .multipart(body)?;
 
     match mailer().send(email).await {
         Ok(_) => Ok(()),
diff --git a/src/static/templates/email/email_footer.hbs b/src/static/templates/email/email_footer.hbs
index 33177317fafda32241dc6a00f1bd64e079f1e14f..7bf3068274f960c53d15918d08b4cd7285ff1bcf 100644
--- a/src/static/templates/email/email_footer.hbs
+++ b/src/static/templates/email/email_footer.hbs
@@ -10,7 +10,7 @@
                      <td class="aligncenter social-icons" align="center" style="-webkit-font-smoothing: antialiased; -webkit-text-size-adjust: none; box-sizing: border-box; color: #999; font-family: 'Helvetica Neue', Helvetica, Arial, sans-serif; font-size: 12px; line-height: 20px; margin: 0; padding: 15px 0 0 0;" valign="top">
                         <table cellpadding="0" cellspacing="0" style="-webkit-font-smoothing: antialiased; -webkit-text-size-adjust: none; box-sizing: border-box; color: #333; font-family: 'Helvetica Neue', Helvetica, Arial, sans-serif; font-size: 16px; line-height: 25px; margin: 0 auto;">
                            <tr style="-webkit-font-smoothing: antialiased; -webkit-text-size-adjust: none; box-sizing: border-box; color: #333; font-family: 'Helvetica Neue', Helvetica, Arial, sans-serif; font-size: 16px; line-height: 25px; margin: 0;">
-                                 <td style="-webkit-font-smoothing: antialiased; -webkit-text-size-adjust: none; box-sizing: border-box; color: #999; font-family: 'Helvetica Neue', Helvetica, Arial, sans-serif; font-size: 12px; line-height: 20px; margin: 0; padding: 0 10px;" valign="top"><a href="https://github.com/dani-garcia/vaultwarden" target="_blank" style="-webkit-font-smoothing: antialiased; -webkit-text-size-adjust: none; box-sizing: border-box; color: #999; font-family: 'Helvetica Neue', Helvetica, Arial, sans-serif; font-size: 12px; line-height: 20px; margin: 0; text-decoration: underline;"><img src="{{url}}/vw_static/mail-github.png" alt="GitHub" width="30" height="30" style="-webkit-font-smoothing: antialiased; -webkit-text-size-adjust: none; border: none; box-sizing: border-box; color: #333; font-family: 'Helvetica Neue', Helvetica, Arial, sans-serif; font-size: 16px; line-height: 25px; margin: 0; max-width: 100%;" /></a></td>
+                                 <td style="-webkit-font-smoothing: antialiased; -webkit-text-size-adjust: none; box-sizing: border-box; color: #999; font-family: 'Helvetica Neue', Helvetica, Arial, sans-serif; font-size: 12px; line-height: 20px; margin: 0; padding: 0 10px;" valign="top"><a href="https://github.com/dani-garcia/vaultwarden" target="_blank" style="-webkit-font-smoothing: antialiased; -webkit-text-size-adjust: none; box-sizing: border-box; color: #999; font-family: 'Helvetica Neue', Helvetica, Arial, sans-serif; font-size: 12px; line-height: 20px; margin: 0; text-decoration: underline;"><img src="{{img_src}}mail-github.png" alt="GitHub" width="30" height="30" style="-webkit-font-smoothing: antialiased; -webkit-text-size-adjust: none; border: none; box-sizing: border-box; color: #333; font-family: 'Helvetica Neue', Helvetica, Arial, sans-serif; font-size: 16px; line-height: 25px; margin: 0; max-width: 100%;" /></a></td>
                            </tr>
                         </table>
                      </td>
diff --git a/src/static/templates/email/email_header.hbs b/src/static/templates/email/email_header.hbs
index a1e7cc27e349081cf5e5950e362449d14923ea5d..811f997d931e16743ceea66d2826f08195905c56 100644
--- a/src/static/templates/email/email_header.hbs
+++ b/src/static/templates/email/email_header.hbs
@@ -81,7 +81,7 @@
       <table class="body-wrap" cellpadding="0" cellspacing="0" style="-webkit-font-smoothing: antialiased; -webkit-text-size-adjust: none; box-sizing: border-box; color: #333; font-family: 'Helvetica Neue', Helvetica, Arial, sans-serif; font-size: 16px; line-height: 25px; margin: 0; width: 100%;" bgcolor="#f6f6f6">
          <tr style="-webkit-font-smoothing: antialiased; -webkit-text-size-adjust: none; box-sizing: border-box; color: #333; font-family: 'Helvetica Neue', Helvetica, Arial, sans-serif; font-size: 16px; line-height: 25px; margin: 0;">
             <td valign="middle" class="aligncenter middle logo" style="-webkit-font-smoothing: antialiased; -webkit-text-size-adjust: none; box-sizing: border-box; color: #333; font-family: 'Helvetica Neue', Helvetica, Arial, sans-serif; font-size: 16px; line-height: 25px; margin: 0; padding: 20px 0 10px;" align="center">
-                <img src="{{url}}/vw_static/logo-gray.png" alt="" width="190" height="39" style="-webkit-font-smoothing: antialiased; -webkit-text-size-adjust: none; border: none; box-sizing: border-box; color: #333; font-family: 'Helvetica Neue', Helvetica, Arial, sans-serif; font-size: 16px; line-height: 25px; margin: 0; max-width: 100%;" />
+                <img src="{{img_src}}logo-gray.png" alt="Vaultwarden" width="190" height="39" style="-webkit-font-smoothing: antialiased; -webkit-text-size-adjust: none; border: none; box-sizing: border-box; color: #333; font-family: 'Helvetica Neue', Helvetica, Arial, sans-serif; font-size: 16px; line-height: 25px; margin: 0; max-width: 100%;" />
             </td>
          </tr>
          <tr style="-webkit-font-smoothing: antialiased; -webkit-text-size-adjust: none; box-sizing: border-box; color: #333; font-family: 'Helvetica Neue', Helvetica, Arial, sans-serif; font-size: 16px; line-height: 25px; margin: 0;">