@@ -242,6 +242,12 @@ before(
 	from: /(\A|@)#{CONFIG[:sgx]}(\/|\Z)/
 ) { |iq| halt if IQ_MANAGER.fulfill(iq) }
 
+SPAM_ERRS = [
+	"rejected-spam-detected",
+	"destination-spam-detected",
+	"destination-rejected-due-to-spam-detection"
+].freeze
+
 before nil, to: /\Acustomer_/, from: /(\A|@)#{CONFIG[:sgx]}(\/|\Z)/ do |s|
 	StatsD.increment("stanza_customer")
 
@@ -249,6 +255,17 @@ before nil, to: /\Acustomer_/, from: /(\A|@)#{CONFIG[:sgx]}(\/|\Z)/ do |s|
 	CustomerRepo.new(set_user: Sentry.method(:set_user)).find(
 		s.to.node.delete_prefix("customer_")
 	).then do |customer|
+		if s.is_a?(Blather::Stanza::Message) && s.error?
+			err = Blather::StanzaError.import(s).text
+			if SPAM_ERRS.include?(err)
+				REDIS.setex(
+					"jmp_customer_spam_detected-#{customer.customer_id}",
+					30 * 60,
+					err
+				)
+			end
+		end
+
 		ReachabilityRepo::SMS.new
 			.find(customer, s.from.node, stanza: s).then do |reach|
 				reach.filter do
@@ -361,14 +378,14 @@ message do |m|
 			end
 
 			EMPromise.all([
+				REDIS.exists("jmp_customer_spam_detected-#{customer.customer_id}"),
 				TrustLevelRepo.new.find(customer),
 				customer.message_usage((today..today))
-			]).then { |(tl, usage)|
+			]).then { |(spam, tl, usage)|
+				raise OverLimit.new(customer, "SPAM DETECTED") if spam.to_i == 1
 				raise OverLimit.new(customer, usage) unless tl.send_message?(usage)
 			}.then do
-				EMPromise.all([
-					customer.incr_message_usage, customer.stanza_from(m)
-				])
+				EMPromise.all([customer.incr_message_usage, customer.stanza_from(m)])
 			end
 		}.catch_only(OverLimit) { |e|
 			e.notify_admin