I used this tip, but then went a slightly different direction by using a deadletter queue. For me, it was more explicit than putting the message at the end of the queue.
<rabbit:queue name="content.variantchange.queue" durable="true" queue-arguments="queueArguments"/>
<util:map id="queueArguments">
<entry key="x-dead-letter-exchange" value="content.deadletter.topic"/>
</util:map>
<rabbit:fanout-exchange name="content.deadletter.topic">
<rabbit:bindings>
<rabbit:binding queue="content.deadletter.queue"/>
</rabbit:bindings>
</rabbit:fanout-exchange>
<rabbit:queue name="content.deadletter.queue" durable="true"/>
Once you have the dead letter queue in place, you can do whatever you want via another consumer (including adding it back to the original queue.)
I also ended up using the stateless version of the interceptor Gary recommended which allowed me to not have to worry about a message id generator.
<bean id="retryInterceptor" class="org.springframework.amqp.rabbit.config.StatelessRetryOperationsInterceptorFactoryBean">
<property name="messageRecoverer" ref="rejectAndDontRequeueRecoverer"/>
<property name="retryOperations" ref="retryTemplate" />
</bean>