diff --git a/src/email.rs b/src/email.rs
index 202118efe54efbc07835bb54eb9d14d24868d3a9..b03861153f23aa0fdb0c616c88ef870426db4b6c 100644
--- a/src/email.rs
+++ b/src/email.rs
@@ -1,5 +1,6 @@
 use reqwest::blocking::Client;
 use std::collections::HashMap;
+use std::env;
 
 pub fn send_email(target: String, subject: String, body: String, html: String) -> Result<(), ()> {
 	let mut map = HashMap::new();
@@ -16,3 +17,32 @@ pub fn send_email(target: String, subject: String, body: String, html: String) -
 			Err(_) => Err(())
 		}
 }
+
+fn public_uri() -> String {
+	env::var("PUBLIC_URI").expect("PUBLIC_URI not in environment variables!")
+}
+
+pub fn send_verification_email(email: String, code: String) -> bool {
+	let url = format!("{}/api/account/verify/{}", public_uri(), code);
+	match send_email(
+		email,
+		"Verify your email!".to_string(),
+		format!("Verify your email here: {}", url).to_string(),
+		format!("<a href=\"{}\">Click to verify your email!</a>", url).to_string()
+	) {
+		Ok(_) => true,
+		Err(_) => false,
+	}
+}
+
+pub fn send_welcome_email(email: String, username: String) -> bool {
+	match send_email(
+		email,
+		"Welcome to REVOLT!".to_string(),
+		format!("Welcome, {}! You can now use REVOLT.", username.clone()).to_string(),
+		format!("<b>Welcome, {}!</b><br/>You can now use REVOLT.<br/><a href=\"{}\">Go to REVOLT</a>", username.clone(), public_uri()).to_string()
+	) {
+		Ok(_) => true,
+		Err(_) => false,
+	}
+}
diff --git a/src/routes/account.rs b/src/routes/account.rs
index 9a40c5b0dbc21e142873c685309ce40c4854a935..557704d8c42422988895e12a9a4efe5f56f0bda0 100644
--- a/src/routes/account.rs
+++ b/src/routes/account.rs
@@ -78,23 +78,13 @@ pub fn create(info: Json<Create>) -> JsonValue {
 			"email_verification": {
 				"verified": false,
 				"target": info.email.clone(),
-				"expiry": UtcDatetime(Utc::now() + chrono::Duration::seconds(1)),
+				"expiry": UtcDatetime(Utc::now() + chrono::Duration::days(1)),
 				"rate_limit": UtcDatetime(Utc::now() + chrono::Duration::minutes(1)),
 				"code": code.clone(),
 			}
 		}, None) {
 			Ok(_) => {
-				let url = format!("http://192.168.0.10:5500/api/account/verify/{}", code);
-				let sent =
-					match email::send_email(
-						info.email.clone(),
-						"Verify your email!".to_string(),
-						format!("Verify your email here: {}", url).to_string(),
-						format!("<a href=\"{}\">Click to verify your email!</a>", url).to_string()
-					) {
-						Ok(_) => true,
-						Err(_) => false,
-					};
+				let sent = email::send_verification_email(info.email.clone(), code);
 
 				json!({
 					"success": true,
@@ -145,12 +135,17 @@ pub fn verify_email(code: String) -> JsonValue {
 						},
 						"$set": {
 							"email_verification.verified": true,
-							"email": target,
+							"email": target.clone(),
 						},
 					},
 					None,
 				).expect("Failed to update user!");
 
+				email::send_welcome_email(
+					target.to_string(),
+					u.get_str("username").expect("Failed to retrieve username.").to_string()
+				);
+
 				json!({
 					"success": true
 				})
@@ -162,3 +157,65 @@ pub fn verify_email(code: String) -> JsonValue {
 			})
 		}
 }
+
+#[derive(Serialize, Deserialize)]
+pub struct Resend {
+	email: String,
+}
+
+/// resend a verification email
+/// (1) check if verification is pending for x email
+/// (2) check for rate limit
+/// (3) resend the email
+#[post("/resend", data = "<info>")]
+pub fn resend_email(info: Json<Resend>) -> JsonValue { 
+	let col = database::get_db().collection("users");
+
+	if let Some(u) =
+		col.find_one(doc! { "email_verification.target": info.email.clone() }, None).expect("Failed user lookup") {
+			let ev = u.get_document("email_verification").expect("Missing email_verification on user object!");
+			let rate_limit = ev.get_utc_datetime("rate_limit").expect("Missing rate_limit on email_verification!");
+
+			if Utc::now() < *rate_limit {
+				json!({
+					"success": false,
+					"error": "Hit rate limit! Please try again in a minute or so."
+				})
+			} else {
+				let code = rand::thread_rng()
+					.sample_iter(&Alphanumeric)
+					.take(48)
+					.collect::<String>();
+
+				col.update_one(
+					doc! { "_id": u.get_str("_id").expect("Failed to retrieve user id.") },
+					doc! {
+						"$set": {
+							"email_verification.code": code.clone(),
+							"email_verification.expiry": UtcDatetime(Utc::now() + chrono::Duration::days(1)),
+							"email_verification.rate_limit": UtcDatetime(Utc::now() + chrono::Duration::minutes(1)),
+						},
+					},
+					None,
+				).expect("Failed to update user!");
+
+				match email::send_verification_email(
+					info.email.to_string(),
+					code,
+				) {
+					true => json!({
+						"success": true,
+					}),
+					false => json!({
+						"success": false,
+						"error": "Failed to send email! Likely an issue with the backend API."
+					})
+				}
+			}
+		} else {
+			json!({
+				"success": false,
+				"error": "Email not pending verification!",
+			})
+		}
+}
diff --git a/src/routes/mod.rs b/src/routes/mod.rs
index 4ae3e54b3273ec18366cb74941a5bf54ac8dbd75..3d871f3a39e2d9985f8f148ef0251a6b3138d71d 100644
--- a/src/routes/mod.rs
+++ b/src/routes/mod.rs
@@ -4,5 +4,5 @@ mod account;
 
 pub fn mount(rocket: Rocket) -> Rocket {
 	rocket
-		.mount("/api/account", routes![ account::root, account::create, account::verify_email ])
+		.mount("/api/account", routes![ account::root, account::create, account::verify_email, account::resend_email ])
 }