diff --git a/src/metabase/analytics/prometheus.clj b/src/metabase/analytics/prometheus.clj
index 61d6ce60653b7a8d23af1095335249b381c874ce..f32270a4b7ab99cf0d2297230af9e2f24e18d454 100644
--- a/src/metabase/analytics/prometheus.clj
+++ b/src/metabase/analytics/prometheus.clj
@@ -6,12 +6,12 @@
   Api is quite simple: [[setup!]] and [[shutdown!]]. After that you can retrieve metrics from
   http://localhost:<prometheus-server-port>/metrics."
   (:require
+   [clojure.java.jmx :as jmx]
    [iapetos.collector :as collector]
    [iapetos.collector.ring :as collector.ring]
    [iapetos.core :as prometheus]
    [metabase.models.setting :as setting :refer [defsetting]]
    [metabase.server :as server]
-   [metabase.troubleshooting :as troubleshooting]
    [metabase.util.i18n :refer [deferred-trs trs]]
    [metabase.util.log :as log]
    [potemkin :as p]
@@ -22,6 +22,7 @@
    (io.prometheus.client.hotspot GarbageCollectorExports MemoryPoolsExports StandardExports ThreadExports)
    (io.prometheus.client.jetty JettyStatisticsCollector)
    (java.util ArrayList List)
+   (javax.management ObjectName)
    (org.eclipse.jetty.server Server)))
 
 (set! *warn-on-reflection* true)
@@ -44,8 +45,6 @@
                                                raw-value))))]
                   (setting/get-raw-value :prometheus-server-port integer? parse))))
 
-(defonce ^:private ^{:doc "Prometheus System for prometheus metrics"} system nil)
-
 (p.types/defprotocol+ PrometheusActions
   (stop-web-server [this]))
 
@@ -57,6 +56,8 @@
     (when-let [^Server web-server web-server]
       (.stop web-server))))
 
+(defonce ^:private ^{:doc "Prometheus System for prometheus metrics"} ^PrometheusSystem system nil)
+
 (declare setup-metrics! start-web-server!)
 
 (defn- make-prometheus-system
@@ -64,7 +65,7 @@
   serving metrics from that port."
   [port registry-name]
   (try
-    (let [registry (setup-metrics! registry-name)
+    (let [registry   (setup-metrics! registry-name)
           web-server (start-web-server! port registry)]
       (->PrometheusSystem registry web-server))
     (catch Exception e
@@ -75,7 +76,7 @@
 ;;; Collectors
 
 (defn c3p0-stats
-  "Takes `raw-stats` from [[metabase.troubleshooting/connection-pool-info]] and groups by each property type rather than each database.
+  "Takes `raw-stats` from [[connection-pool-info]] and groups by each property type rather than each database.
   {\"metabase-postgres-app-db\" {:numConnections 15,
                                  :numIdleConnections 15,
                                  :numBusyConnections 0,
@@ -142,11 +143,21 @@
                        raw-label))))
     arr))
 
+(defn- conn-pool-bean-diag-info [acc ^ObjectName jmx-bean]
+  (let [bean-id   (.getCanonicalName jmx-bean)
+        props     [:numConnections :numIdleConnections :numBusyConnections
+                   :minPoolSize :maxPoolSize :numThreadsAwaitingCheckoutDefaultUser]]
+    (assoc acc (jmx/read bean-id :dataSourceName) (jmx/read bean-id props))))
+
+(defn connection-pool-info
+  "Builds a map of info about the current c3p0 connection pools managed by this Metabase instance."
+  []
+  (reduce conn-pool-bean-diag-info {} (jmx/mbean-names "com.mchange.v2.c3p0:type=PooledDataSource,*")))
+
 (def c3p0-collector
   "c3p0 collector delay"
   (letfn [(collect-metrics []
-            (-> (troubleshooting/connection-pool-info)
-                :connection-pools
+            (-> (connection-pool-info)
                 c3p0-stats
                 stats->prometheus))]
     (delay
@@ -192,7 +203,12 @@
     (apply prometheus/register registry
            (concat (jvm-collectors)
                    (jetty-collectors)
-                   [@c3p0-collector]))))
+                   [@c3p0-collector]
+                   ; Iapetos will use "default" if we do not provide a namespace, so explicitly set `metabase-email`:
+                   [(prometheus/counter :metabase-email/messages
+                                        {:description (trs "Number of emails sent.")})
+                    (prometheus/counter :metabase-email/message-errors
+                                        {:description (trs "Number of errors when sending emails.")})]))))
 
 (defn- start-web-server!
   "Start the prometheus web-server. If [[prometheus-server-port]] is not set it will throw."
@@ -229,11 +245,19 @@
     (locking #'system
       (when system
         (try (stop-web-server system)
+             (prometheus/clear (.-registry system))
              (alter-var-root #'system (constantly nil))
              (log/info (trs "Prometheus web-server shut down"))
              (catch Exception e
                (log/warn e (trs "Error stopping prometheus web-server"))))))))
 
+#_{:clj-kondo/ignore [:redefined-var]}
+(defn inc
+  "Call iapetos.core/inc on the metric in the global registry,
+   if it has already been initialized and the metric is registered."
+  [metric]
+  (some-> system .-registry metric prometheus/inc))
+
 (comment
   (require 'iapetos.export)
   (spit "metrics" (iapetos.export/text-format (.registry system))))
diff --git a/src/metabase/api/util.clj b/src/metabase/api/util.clj
index d62369ad350a09843c4de5885eac2af8135e137f..eb5e0009196b02a778a07909a6f8402c691cbf5e 100644
--- a/src/metabase/api/util.clj
+++ b/src/metabase/api/util.clj
@@ -4,6 +4,7 @@
   (:require
    [compojure.core :refer [GET POST]]
    [crypto.random :as crypto-random]
+   [metabase.analytics.prometheus :as prometheus]
    [metabase.analytics.stats :as stats]
    [metabase.api.common :as api]
    [metabase.api.common.validation :as validation]
@@ -54,8 +55,8 @@
   "Returns database connection pool info for the current Metabase instance."
   []
   (validation/check-has-application-permission :monitoring)
-  (let [pool-info (troubleshooting/connection-pool-info)
+  (let [pool-info (prometheus/connection-pool-info)
         headers   {"Content-Disposition" "attachment; filename=\"connection_pool_info.json\""}]
-    (assoc (response/response pool-info) :headers headers, :status 200)))
+    (assoc (response/response {:connection-pools pool-info}) :headers headers, :status 200)))
 
 (api/define-routes)
diff --git a/src/metabase/email.clj b/src/metabase/email.clj
index 1202586f78651acdc736af9680ab5d37b18ea1b5..e87062ef1366912dc6ee83fa47fbbe9edfb36e91 100644
--- a/src/metabase/email.clj
+++ b/src/metabase/email.clj
@@ -1,5 +1,6 @@
 (ns metabase.email
   (:require
+   [metabase.analytics.prometheus :as prometheus]
    [metabase.models.setting :as setting :refer [defsetting]]
    [metabase.util :as u]
    [metabase.util.i18n :refer [deferred-tru trs tru]]
@@ -121,23 +122,29 @@
   does not catch and swallow thrown exceptions, it will bubble up."
   {:style/indent 0}
   [{:keys [subject recipients message-type message]} :- EmailMessage]
-  (when-not (email-smtp-host)
-    (throw (ex-info (tru "SMTP host is not set.") {:cause :smtp-host-not-set})))
-  ;; Now send the email
-  (send-email! (smtp-settings)
-               (merge
-                {:from    (if-let [from-name (email-from-name)]
-                            (str from-name " <" (email-from-address) ">")
-                            (email-from-address))
-                 :to      recipients
-                 :subject subject
-                 :body    (case message-type
-                            :attachments message
-                            :text        message
-                            :html        [{:type    "text/html; charset=utf-8"
-                                           :content message}])}
-                (when-let [reply-to (email-reply-to)]
-                  {:reply-to reply-to}))))
+  (try
+    (when-not (email-smtp-host)
+      (throw (ex-info (tru "SMTP host is not set.") {:cause :smtp-host-not-set})))
+    ;; Now send the email
+    (send-email! (smtp-settings)
+                 (merge
+                  {:from    (if-let [from-name (email-from-name)]
+                              (str from-name " <" (email-from-address) ">")
+                              (email-from-address))
+                   :to      recipients
+                   :subject subject
+                   :body    (case message-type
+                              :attachments message
+                              :text        message
+                              :html        [{:type    "text/html; charset=utf-8"
+                                             :content message}])}
+                  (when-let [reply-to (email-reply-to)]
+                    {:reply-to reply-to})))
+    (catch Throwable e
+      (prometheus/inc :metabase-email/message-errors)
+      (throw e))
+    (finally
+      (prometheus/inc :metabase-email/messages))))
 
 (def ^:private SMTPStatus
   "Schema for the response returned by various functions in [[metabase.email]]. Response will be a map with the key
diff --git a/src/metabase/troubleshooting.clj b/src/metabase/troubleshooting.clj
index 02cf58d6b755ff8b7afac3f53a4818fcbe11e00d..ebc949a32e71aa0c65ac2fa355c4addff465b55e 100644
--- a/src/metabase/troubleshooting.clj
+++ b/src/metabase/troubleshooting.clj
@@ -1,13 +1,10 @@
 (ns metabase.troubleshooting
   (:require
-   [clojure.java.jmx :as jmx]
    [metabase.analytics.stats :as stats]
    [metabase.config :as config]
    [metabase.db :as mdb]
    [metabase.driver :as driver]
-   [toucan2.core :as t2])
-  (:import
-   (javax.management ObjectName)))
+   [toucan2.core :as t2]))
 
 (set! *warn-on-reflection* true)
 
@@ -43,15 +40,3 @@
    :run-mode                     (config/config-kw :mb-run-mode)
    :version                      config/mb-version-info
    :settings                     {:report-timezone (driver/report-timezone)}})
-
-(defn- conn-pool-bean-diag-info [acc ^ObjectName jmx-bean]
-  (let [bean-id   (.getCanonicalName jmx-bean)
-        props     [:numConnections :numIdleConnections :numBusyConnections
-                   :minPoolSize :maxPoolSize :numThreadsAwaitingCheckoutDefaultUser]]
-      (assoc acc (jmx/read bean-id :dataSourceName) (jmx/read bean-id props))))
-
-(defn connection-pool-info
-  "Builds a map of info about the current c3p0 connection pools managed by this Metabase instance."
-  []
-  (->> (reduce conn-pool-bean-diag-info {} (jmx/mbean-names "com.mchange.v2.c3p0:type=PooledDataSource,*"))
-       (assoc {} :connection-pools)))
diff --git a/test/metabase/analytics/prometheus_test.clj b/test/metabase/analytics/prometheus_test.clj
index a3660938db1739377fb20b926453ec9ba3353013..4571afa302423d0d4a7081cfdeced056e1be6c08 100644
--- a/test/metabase/analytics/prometheus_test.clj
+++ b/test/metabase/analytics/prometheus_test.clj
@@ -6,10 +6,11 @@
    [clojure.test :refer :all]
    [iapetos.registry :as registry]
    [metabase.analytics.prometheus :as prometheus]
-   [metabase.test.fixtures :as fixtures]
-   [metabase.troubleshooting :as troubleshooting])
+   [metabase.test.fixtures :as fixtures])
   (:import
-   (io.prometheus.client Collector GaugeMetricFamily)
+   (iapetos.registry IapetosRegistry)
+   (io.prometheus.client Collector Collector$MetricFamilySamples CollectorRegistry GaugeMetricFamily)
+   (metabase.analytics.prometheus PrometheusSystem)
    (org.eclipse.jetty.server Server)))
 
 (set! *warn-on-reflection* true)
@@ -104,8 +105,9 @@
          (#'prometheus/make-prometheus-system 0 (name (gensym "test-registry")))
          server#  ^Server (.web-server ~system)
          ~port   (.. server# getURI getPort)]
-     (try ~@body
-          (finally (prometheus/stop-web-server ~system)))))
+     (with-redefs [prometheus/system ~system]
+       (try ~@body
+            (finally (prometheus/stop-web-server ~system))))))
 
 (deftest web-server-test
   (testing "Can get metrics from the web-server"
@@ -128,7 +130,7 @@
                                                    :namespace "metabase_database"}
                                          nil)]
         (is c3p0-collector "c3p0 stats not found"))))
-  (testing "Registry has an entry for each database in [[troubleshooting/connection-pool-info]]"
+  (testing "Registry has an entry for each database in [[prometheus/connection-pool-info]]"
     (with-prometheus-system [_ system]
       (let [registry       (.registry system)
             c3p0-collector (registry/get registry {:name      "c3p0_stats"
@@ -138,12 +140,12 @@
             measurements   (.collect ^Collector c3p0-collector)
             _              (is (pos? (count measurements))
                                "No measurements taken")]
-        (is (= (count (:connection-pools (troubleshooting/connection-pool-info)))
+        (is (= (count (prometheus/connection-pool-info))
                (count (.samples ^GaugeMetricFamily (first measurements))))
             "Expected one entry per database for each measurement"))))
   (testing "Registry includes c3p0 stats"
     (with-prometheus-system [port _]
-      (let [[db-name values] (first (:connection-pools (troubleshooting/connection-pool-info)))
+      (let [[db-name values] (first (prometheus/connection-pool-info))
             tag-name         (comp :label #'prometheus/label-translation)
             expected-lines   (set (for [[tag value] values]
                                     (format "%s{database=\"%s\",} %s"
@@ -152,3 +154,27 @@
                                    (metric-lines port))]
         (is (seq (set/intersection expected-lines actual-lines))
             "Registry does not have c3p0 metrics in it")))))
+
+(deftest email-collector-test
+  (testing "Registry has email metrics registered"
+    (with-prometheus-system [_ system]
+      (let [sample-names (set (for [metric-family-samples (enumeration-seq (.metricFamilySamples ^CollectorRegistry (.raw ^IapetosRegistry (.-registry system))))
+                                    sample-name           (.getNames ^Collector$MetricFamilySamples metric-family-samples)]
+                                sample-name))]
+        (is (contains? sample-names "metabase_email_messages") "messages sample not found")
+        (is (contains? sample-names "metabase_email_message_errors") "message_errors sample not found")))))
+
+(defn- get-sample-value
+  [^PrometheusSystem system ^String metric]
+  (.getSampleValue ^CollectorRegistry (registry/raw (.-registry system)) metric))
+
+(deftest inc-server-test
+  (testing "inc has no effect if system is not setup"
+    (prometheus/inc :metabase-email/messages)) ; << Does not throw.
+  (testing "inc has no effect when called with unknown metric"
+    (with-prometheus-system [_ _system]
+      (prometheus/inc :metabase-email/unknown-metric))) ; << Does not throw.
+  (testing "inc is recorded for known metrics"
+    (with-prometheus-system [_ system]
+      (prometheus/inc :metabase-email/messages)
+      (is (< 0 (get-sample-value system "metabase_email_messages_total"))))))
diff --git a/test/metabase/email_test.clj b/test/metabase/email_test.clj
index 7020dd3cf8f03063390b064f37f6af6124bf6ac7..f80324c0b41716ebf8d93a089a65d8a0b5890e7d 100644
--- a/test/metabase/email_test.clj
+++ b/test/metabase/email_test.clj
@@ -4,6 +4,7 @@
    [clojure.java.io :as io]
    [clojure.test :refer :all]
    [medley.core :as m]
+   [metabase.analytics.prometheus :as prometheus]
    [metabase.email :as email]
    [metabase.test.data.users :as test.users]
    [metabase.test.util :as tu]
@@ -237,6 +238,28 @@
               :message-type :html
               :message      "101. Metabase will make you a better person")
              (@inbox "test@test.com")))))
+    (testing "metrics collection"
+      (let [calls (atom nil)]
+        (with-redefs [prometheus/inc #(swap! calls conj %)]
+          (with-fake-inbox
+            (email/send-message!
+             :subject      "101 Reasons to use Metabase"
+             :recipients   ["test@test.com"]
+             :message-type :html
+             :message      "101. Metabase will make you a better person")))
+        (is (= 1 (count (filter #{:metabase-email/messages} @calls))))
+        (is (= 0 (count (filter #{:metabase-email/message-errors} @calls))))))
+    (testing "error metrics collection"
+      (let [calls (atom nil)]
+        (with-redefs [prometheus/inc #(swap! calls conj %)
+                      email/send-email! (fn [_ _] (throw (Exception. "test-exception")))]
+          (email/send-message!
+            :subject      "101 Reasons to use Metabase"
+            :recipients   ["test@test.com"]
+            :message-type :html
+            :message      "101. Metabase will make you a better person"))
+        (is (= 1 (count (filter #{:metabase-email/messages} @calls))))
+        (is (= 1 (count (filter #{:metabase-email/message-errors} @calls))))))
     (testing "basic sending without email-from-name"
       (tu/with-temporary-setting-values [email-from-name nil]
         (is (=