{"id":20397,"date":"2026-09-14T23:34:31","date_gmt":"2026-09-14T23:34:31","guid":{"rendered":"https:\/\/www.mailgun.com\/blog\/configurar-cola-mensajes-envio-asincrono\/"},"modified":"2026-09-14T23:34:31","modified_gmt":"2026-09-14T23:34:31","slug":"configurar-cola-mensajes-envio-asincrono","status":"publish","type":"blog","link":"https:\/\/www.mailgun.com\/es\/blog\/email\/configurar-cola-mensajes-envio-asincrono\/","title":{"rendered":"C\u00f3mo configurar colas de mensajes para el env\u00edo as\u00edncrono"},"content":{"rendered":"\n<p class=\"wp-block-paragraph\">La gesti\u00f3n de colas de mensajes es una herramienta interesante que puede ayudarnos a crear sitios web o servicios web escalables. Una cola de mensajes permite a las aplicaciones comunicarse de forma as\u00edncrona mediante el env\u00edo de mensajes entre s\u00ed.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">A grandes rasgos, la gesti\u00f3n de colas de mensajes es bastante sencilla. Un proceso, llamado Productor, publica mensajes en una cola, donde se almacenan hasta que un proceso Consumidor est\u00e1 listo para consumirlos.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Publicar mensajes en un br\u00f3ker de mensajes es una operaci\u00f3n muy r\u00e1pida y podemos aprovecharlo para acelerar nuestros servicios web. En su lugar, podemos delegar algunas tareas a procesos en segundo plano haciendo que nuestro servicio web publique un mensaje en una cola. A continuaci\u00f3n, podemos hacer que procesos consumidores en segundo plano consuman los mensajes y realicen las tareas delegadas seg\u00fan sea necesario.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">En esta gu\u00eda utilizaremos\u00a0<a href=\"https:\/\/www.rabbitmq.com\/\" target=\"_tabs\" rel=\"noopener noreferrer\">RabbitMQ<\/a>\u00a0como br\u00f3ker de mensajes. Integraremos RabbitMQ en una aplicaci\u00f3n Flask de ejemplo para posponer el env\u00edo del email a un proceso en segundo plano. La aplicaci\u00f3n, Flaskr, puede que te resulte familiar si ya has completado el\u00a0<a href=\"http:\/\/flask.pocoo.org\/docs\/0.12\/tutorial\/introduction\/\" target=\"_tabs\" rel=\"noopener noreferrer\">Tutorial de Flask<\/a>.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Echemos un vistazo a nuestra funci\u00f3n de vista de registro:<\/p>\n\n\n    <div data-content-type=\"longform\" class=\"code-snippet longform-spacings rounded-lg overflow-hidden shadow \" data-count=\"1\">\r\n        <ul class=\"nav nav-buttons code-snippet__tabs longform-except position-relative d-flex gap-2 flex-wrap p-3\" role=\"tablist\">\r\n\r\n                            \r\n                    \r\n                        <li class=\"nav-item\" role=\"presentation\">\r\n                            <button class=\"nav-link active\" data-bs-toggle=\"tab\" data-bs-target=\"#code_0\" type=\"button\" role=\"tab\" aria-controls=\"code_0\" aria-selected=\"true\">\r\n                                Python                            <\/button>\r\n                        <\/li>\r\n\r\n                    \r\n                            \r\n        <\/ul>\r\n        <div class=\"code-snippet__tab-content tab-content\">\r\n\r\n                            \r\n                    <div class=\"tab-pane show active\" id=\"code_0\" role=\"tabpanel\" aria-labelledby=\"code_0\">\r\n                        <div class=\"code-snippet__code-wrapper\">\r\n                            <div class=\"nav nav-buttons code-snippet__copy-wrapper\">\r\n                                <button type=\"button\" class=\"nav-link code-snippet__copy\" data-clipboard-target=\"#code_0_content\" data-clipboard-label=\"Copia al portapapeles\" data-clipboard-success-label=\"\u00a1Copiado!\" data-clipboard-error-label=\"No se ha podido copiar\" data-tooltip=\"Copia al portapapeles\" data-tooltip-placement=\"left\" role=\"tooltip\" aria-label=\"Copia al portapapeles\">\r\n                                    <svg class=\"code-snippet__copy-icon code-snippet__copy-icon--default\" width=\"24\" height=\"24\" aria-hidden=\"true\" data-url=\"https:\/\/www.mailgun.com\/wp-content\/plugins\/sinch-core\/assets\/icons\/sinch\/file-stack.svg\"><\/svg>\r\n                                    <svg class=\"code-snippet__copy-icon code-snippet__copy-icon--success\" width=\"24\" height=\"24\" aria-hidden=\"true\" data-url=\"https:\/\/www.mailgun.com\/wp-content\/plugins\/sinch-core\/assets\/icons\/sinch\/badge-check.svg\"><\/svg>\r\n                                <\/button>\r\n                            <\/div>\r\n                            <pre class=\"w-100 h-100 m-0 line-numbers language-Python\">\r\n                                <code id=\"code_0_content\" class=\"language-Python\">\r\n\r\n                                    @app.route(&#039;\/signup&#039;, methods=[&#039;GET&#039;, &#039;POST&#039;])                                  \r\ndef signup():  \r\n    error = None                                                                \r\n    if request.method == &#039;POST&#039;:                                                \r\n        email = request.form[&#039;email&#039;]                                           \r\n        password = request.form[&#039;password&#039;]                                     \r\n        if not (email or password):                                             \r\n            return signup_error(&#039;Email Address and Password are required.&#039;)        \r\n        db = get_db()                                                              \r\n        c = db.cursor()                                                            \r\n        c.execute(&#039;SELECT * FROM users WHERE email=?;&#039;, (email,))                  \r\n        if c.fetchone():                                                           \r\n            return signup_error(&#039;Email Addres already has an account.&#039;)            \r\n        c.execute(&#039;INSERT INTO users (email, password) VALUES (?, ?);&#039;,            \r\n                  (email, pbkdf2_sha256.hash(password)))                           \r\n        db.commit()                                                                  \r\n        send_welcome_email(email)                                                  \r\n        flash(&#039;Account Created&#039;)                                                   \r\n        return redirect(url_for(&#039;login&#039;))                                          \r\n    else:                                                                          \r\n        return render_template(&#039;signup.html&#039;)                                      \r\n\r\ndef send_welcome_email(address):  \r\n    res = requests.post(                                                           \r\n        &quot;https:\/\/api.mailgun.net\/v3\/{}\/messages&quot;.format(app.config[&#039;DOMAIN&#039;]),  \r\n        auth=(&quot;api&quot;, MAILGUN_API_KEY),                                             \r\n        data={&quot;from&quot;: &quot;Flaskr &quot;.format(app.config[&#039;DOMAIN&#039;]),          \r\n              &quot;to&quot;: [address],                                                     \r\n              &quot;subject&quot;: &quot;Welcome to Flaskr!&quot;,                                     \r\n              &quot;text&quot;: &quot;Welcome to Flaskr, your account is now active!&quot;}            \r\n    )                                                                              \r\n    if res.status_code != 200:                                                     \r\n        # Something terrible happened &lt;img class=&quot;emoji&quot; alt=&quot;\ud83d\ude41&quot; src=&quot;https:\/\/s.w.org\/images\/core\/emoji\/12.0.0-1\/svg\/1f641.svg&quot;&gt;                                          \r\n        raise MailgunError(&quot;{}-{}&quot;.format(res.status_code, res.reason))            \r\n\r\ndef signup_error(error):  \r\n    return render_template(&#039;signup.html&#039;, error=error)\r\n                                <\/code>\r\n                            <\/pre>\r\n                        <\/div>\r\n                    <\/div>\r\n                                    <\/div>\r\n    <\/div>\r\n\n\n\n<p class=\"wp-block-paragraph\">Actualmente, la funci\u00f3n de vista comprueba la base de datos para asegurarse de que no existe ya una cuenta con esa direcci\u00f3n de email y, a continuaci\u00f3n, a\u00f1ade el nuevo usuario a la base de datos. A continuaci\u00f3n, la vista env\u00eda inmediatamente un mensaje de email de bienvenida al usuario antes de finalizar la solicitud.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Hay un par de problemas con esta vista que podemos mejorar con una cola de mensajes. No tenemos que hacer esperar al usuario por una respuesta mientras enviamos el email de bienvenida. Ser\u00eda mejor si pudi\u00e9ramos responder al usuario lo antes posible. Tambi\u00e9n queremos una forma de reintentar el env\u00edo del email de bienvenida si por alguna raz\u00f3n no podemos hacerlo al primer intento.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">En primer lugar, vamos a ejecutar una instancia de RabbitMQ en un contenedor de Docker:<\/p>\n\n\n    <div data-content-type=\"longform\" class=\"code-snippet longform-spacings rounded-lg overflow-hidden shadow \" data-count=\"1\">\r\n        <ul class=\"nav nav-buttons code-snippet__tabs longform-except position-relative d-flex gap-2 flex-wrap p-3\" role=\"tablist\">\r\n\r\n                            \r\n                    \r\n                        <li class=\"nav-item\" role=\"presentation\">\r\n                            <button class=\"nav-link active\" data-bs-toggle=\"tab\" data-bs-target=\"#code_0\" type=\"button\" role=\"tab\" aria-controls=\"code_0\" aria-selected=\"true\">\r\n                                Python                            <\/button>\r\n                        <\/li>\r\n\r\n                    \r\n                            \r\n        <\/ul>\r\n        <div class=\"code-snippet__tab-content tab-content\">\r\n\r\n                            \r\n                    <div class=\"tab-pane show active\" id=\"code_0\" role=\"tabpanel\" aria-labelledby=\"code_0\">\r\n                        <div class=\"code-snippet__code-wrapper\">\r\n                            <div class=\"nav nav-buttons code-snippet__copy-wrapper\">\r\n                                <button type=\"button\" class=\"nav-link code-snippet__copy\" data-clipboard-target=\"#code_0_content\" data-clipboard-label=\"Copia al portapapeles\" data-clipboard-success-label=\"\u00a1Copiado!\" data-clipboard-error-label=\"No se ha podido copiar\" data-tooltip=\"Copia al portapapeles\" data-tooltip-placement=\"left\" role=\"tooltip\" aria-label=\"Copia al portapapeles\">\r\n                                    <svg class=\"code-snippet__copy-icon code-snippet__copy-icon--default\" width=\"24\" height=\"24\" aria-hidden=\"true\" data-url=\"https:\/\/www.mailgun.com\/wp-content\/plugins\/sinch-core\/assets\/icons\/sinch\/file-stack.svg\"><\/svg>\r\n                                    <svg class=\"code-snippet__copy-icon code-snippet__copy-icon--success\" width=\"24\" height=\"24\" aria-hidden=\"true\" data-url=\"https:\/\/www.mailgun.com\/wp-content\/plugins\/sinch-core\/assets\/icons\/sinch\/badge-check.svg\"><\/svg>\r\n                                <\/button>\r\n                            <\/div>\r\n                            <pre class=\"w-100 h-100 m-0 line-numbers language-Python\">\r\n                                <code id=\"code_0_content\" class=\"language-Python\">\r\n\r\n                                        docker run -d --hostname my-rabbit -p 4369:4369 -p 5672:5672  \r\n     -p 35197:35197 --name rabbitmq rabbitmq:3\r\n                                <\/code>\r\n                            <\/pre>\r\n                        <\/div>\r\n                    <\/div>\r\n                                    <\/div>\r\n    <\/div>\r\n\n\n\n<p class=\"wp-block-paragraph\">Ahora vamos a a\u00f1adir algo de c\u00f3digo para inicializar una cola cuando se inicie nuestra aplicaci\u00f3n:<\/p>\n\n\n    <div data-content-type=\"longform\" class=\"code-snippet longform-spacings rounded-lg overflow-hidden shadow \" data-count=\"1\">\r\n        <ul class=\"nav nav-buttons code-snippet__tabs longform-except position-relative d-flex gap-2 flex-wrap p-3\" role=\"tablist\">\r\n\r\n                            \r\n                    \r\n                        <li class=\"nav-item\" role=\"presentation\">\r\n                            <button class=\"nav-link active\" data-bs-toggle=\"tab\" data-bs-target=\"#code_0\" type=\"button\" role=\"tab\" aria-controls=\"code_0\" aria-selected=\"true\">\r\n                                Python                            <\/button>\r\n                        <\/li>\r\n\r\n                    \r\n                            \r\n        <\/ul>\r\n        <div class=\"code-snippet__tab-content tab-content\">\r\n\r\n                            \r\n                    <div class=\"tab-pane show active\" id=\"code_0\" role=\"tabpanel\" aria-labelledby=\"code_0\">\r\n                        <div class=\"code-snippet__code-wrapper\">\r\n                            <div class=\"nav nav-buttons code-snippet__copy-wrapper\">\r\n                                <button type=\"button\" class=\"nav-link code-snippet__copy\" data-clipboard-target=\"#code_0_content\" data-clipboard-label=\"Copia al portapapeles\" data-clipboard-success-label=\"\u00a1Copiado!\" data-clipboard-error-label=\"No se ha podido copiar\" data-tooltip=\"Copia al portapapeles\" data-tooltip-placement=\"left\" role=\"tooltip\" aria-label=\"Copia al portapapeles\">\r\n                                    <svg class=\"code-snippet__copy-icon code-snippet__copy-icon--default\" width=\"24\" height=\"24\" aria-hidden=\"true\" data-url=\"https:\/\/www.mailgun.com\/wp-content\/plugins\/sinch-core\/assets\/icons\/sinch\/file-stack.svg\"><\/svg>\r\n                                    <svg class=\"code-snippet__copy-icon code-snippet__copy-icon--success\" width=\"24\" height=\"24\" aria-hidden=\"true\" data-url=\"https:\/\/www.mailgun.com\/wp-content\/plugins\/sinch-core\/assets\/icons\/sinch\/badge-check.svg\"><\/svg>\r\n                                <\/button>\r\n                            <\/div>\r\n                            <pre class=\"w-100 h-100 m-0 line-numbers language-Python\">\r\n                                <code id=\"code_0_content\" class=\"language-Python\">\r\n\r\n                                    def connect_queue():  \r\n    if not hasattr(g, &#039;rabbitmq&#039;):                                                                    \r\n        g.rabbitmq = pika.BlockingConnection(                                                         \r\n            pika.ConnectionParameters(app.config[&#039;RABBITMQ_HOST&#039;])                                    \r\n        )                                                                                             \r\n    return g.rabbitmq                                                                                 \r\n\r\ndef get_welcome_queue():  \r\n    if not hasattr(g, &#039;welcome_queue&#039;):                                                               \r\n        conn = connect_queue()                                                                        \r\n        channel = conn.channel()                                                                      \r\n        channel.queue_declare(queue=&#039;welcome_queue&#039;, durable=True)                                    \r\n        channel.queue_bind(exchange=&#039;amq.direct&#039;, queue=&#039;welcome_queue&#039;)                              \r\n        g.welcome_queue = channel                                                                     \r\n    return g.welcome_queue                                                                            \r\n\r\n@app.teardown_appcontext                                                                              \r\ndef close_queue(error)  \r\n    if hasattr(g, &#039;rabbitmq&#039;):                                                                        \r\n        g.rabbitmq.close()\r\n                                <\/code>\r\n                            <\/pre>\r\n                        <\/div>\r\n                    <\/div>\r\n                                    <\/div>\r\n    <\/div>\r\n\n\n\n<p class=\"wp-block-paragraph\">Estamos declarando una cola llamada \u201cwelcome_queue\u201d que utilizaremos para enviar mensajes a los workers con la direcci\u00f3n de email a la que se debe enviar el email de bienvenida.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">A continuaci\u00f3n, podemos actualizar nuestra vista de registro para que publique un mensaje en la cola en lugar de enviar el email de bienvenida.<\/p>\n\n\n    <div data-content-type=\"longform\" class=\"code-snippet longform-spacings rounded-lg overflow-hidden shadow \" data-count=\"1\">\r\n        <ul class=\"nav nav-buttons code-snippet__tabs longform-except position-relative d-flex gap-2 flex-wrap p-3\" role=\"tablist\">\r\n\r\n                            \r\n                    \r\n                        <li class=\"nav-item\" role=\"presentation\">\r\n                            <button class=\"nav-link active\" data-bs-toggle=\"tab\" data-bs-target=\"#code_0\" type=\"button\" role=\"tab\" aria-controls=\"code_0\" aria-selected=\"true\">\r\n                                Python                            <\/button>\r\n                        <\/li>\r\n\r\n                    \r\n                            \r\n        <\/ul>\r\n        <div class=\"code-snippet__tab-content tab-content\">\r\n\r\n                            \r\n                    <div class=\"tab-pane show active\" id=\"code_0\" role=\"tabpanel\" aria-labelledby=\"code_0\">\r\n                        <div class=\"code-snippet__code-wrapper\">\r\n                            <div class=\"nav nav-buttons code-snippet__copy-wrapper\">\r\n                                <button type=\"button\" class=\"nav-link code-snippet__copy\" data-clipboard-target=\"#code_0_content\" data-clipboard-label=\"Copia al portapapeles\" data-clipboard-success-label=\"\u00a1Copiado!\" data-clipboard-error-label=\"No se ha podido copiar\" data-tooltip=\"Copia al portapapeles\" data-tooltip-placement=\"left\" role=\"tooltip\" aria-label=\"Copia al portapapeles\">\r\n                                    <svg class=\"code-snippet__copy-icon code-snippet__copy-icon--default\" width=\"24\" height=\"24\" aria-hidden=\"true\" data-url=\"https:\/\/www.mailgun.com\/wp-content\/plugins\/sinch-core\/assets\/icons\/sinch\/file-stack.svg\"><\/svg>\r\n                                    <svg class=\"code-snippet__copy-icon code-snippet__copy-icon--success\" width=\"24\" height=\"24\" aria-hidden=\"true\" data-url=\"https:\/\/www.mailgun.com\/wp-content\/plugins\/sinch-core\/assets\/icons\/sinch\/badge-check.svg\"><\/svg>\r\n                                <\/button>\r\n                            <\/div>\r\n                            <pre class=\"w-100 h-100 m-0 line-numbers language-Python\">\r\n                                <code id=\"code_0_content\" class=\"language-Python\">\r\n\r\n                                    @app.route(&#039;\/signup&#039;, methods=[&#039;GET&#039;, &#039;POST&#039;])                                  \r\ndef signup():  \r\n    error = None                                                                \r\n    if request.method == &#039;POST&#039;:                                                \r\n        email = request.form[&#039;email&#039;]                                           \r\n        password = request.form[&#039;password&#039;]                                     \r\n        if not (email or password):                                             \r\n            return signup_error(&#039;Email Address and Password are required.&#039;)     \r\n        db = get_db()                                                           \r\n        c = db.cursor()                                                         \r\n        c.execute(&#039;SELECT * FROM users WHERE email=?;&#039;, (email,))               \r\n        if c.fetchone():                                                        \r\n            return signup_error(&#039;Email Addres already has an account.&#039;)         \r\n        c.execute(&#039;INSERT INTO users (email, password) VALUES (?, ?);&#039;,         \r\n                  (email, pbkdf2_sha256.hash(password)))                        \r\n        db.commit()                                                             \r\n        q = get_welcome_queue()                                                 \r\n        q.basic_publish(                                                        \r\n            exchange=&#039;amq.direct&#039;,                                              \r\n            routing_key=&#039;welcome_queue&#039;,                                        \r\n            body=email,                                                         \r\n            properties=pika.BasicProperties(                                    \r\n                delivery_mode=_DELIVERY_MODE_PERSISTENT                         \r\n            )                                                                   \r\n        )                                                                       \r\n        flash(&#039;Account Created&#039;)                                                \r\n        return redirect(url_for(&#039;login&#039;))                                       \r\n    else:                                                                       \r\n        return render_template(&#039;signup.html&#039;)\r\n                                <\/code>\r\n                            <\/pre>\r\n                        <\/div>\r\n                    <\/div>\r\n                                    <\/div>\r\n    <\/div>\r\n\n\n\n<p class=\"wp-block-paragraph\">Ahora podemos escribir nuestro c\u00f3digo de worker. Lo mejor de usar una cola de mensajes es que el proceso worker puede ejecutarse en cualquier lugar. Puede ejecutarse en servidores dedicados para workers o quiz\u00e1 junto a tu servicio web. Este ser\u00eda el aspecto de un script worker sencillo:<\/p>\n\n\n    <div data-content-type=\"longform\" class=\"code-snippet longform-spacings rounded-lg overflow-hidden shadow \" data-count=\"1\">\r\n        <ul class=\"nav nav-buttons code-snippet__tabs longform-except position-relative d-flex gap-2 flex-wrap p-3\" role=\"tablist\">\r\n\r\n                            \r\n                    \r\n                        <li class=\"nav-item\" role=\"presentation\">\r\n                            <button class=\"nav-link active\" data-bs-toggle=\"tab\" data-bs-target=\"#code_0\" type=\"button\" role=\"tab\" aria-controls=\"code_0\" aria-selected=\"true\">\r\n                                Python                            <\/button>\r\n                        <\/li>\r\n\r\n                    \r\n                            \r\n        <\/ul>\r\n        <div class=\"code-snippet__tab-content tab-content\">\r\n\r\n                            \r\n                    <div class=\"tab-pane show active\" id=\"code_0\" role=\"tabpanel\" aria-labelledby=\"code_0\">\r\n                        <div class=\"code-snippet__code-wrapper\">\r\n                            <div class=\"nav nav-buttons code-snippet__copy-wrapper\">\r\n                                <button type=\"button\" class=\"nav-link code-snippet__copy\" data-clipboard-target=\"#code_0_content\" data-clipboard-label=\"Copia al portapapeles\" data-clipboard-success-label=\"\u00a1Copiado!\" data-clipboard-error-label=\"No se ha podido copiar\" data-tooltip=\"Copia al portapapeles\" data-tooltip-placement=\"left\" role=\"tooltip\" aria-label=\"Copia al portapapeles\">\r\n                                    <svg class=\"code-snippet__copy-icon code-snippet__copy-icon--default\" width=\"24\" height=\"24\" aria-hidden=\"true\" data-url=\"https:\/\/www.mailgun.com\/wp-content\/plugins\/sinch-core\/assets\/icons\/sinch\/file-stack.svg\"><\/svg>\r\n                                    <svg class=\"code-snippet__copy-icon code-snippet__copy-icon--success\" width=\"24\" height=\"24\" aria-hidden=\"true\" data-url=\"https:\/\/www.mailgun.com\/wp-content\/plugins\/sinch-core\/assets\/icons\/sinch\/badge-check.svg\"><\/svg>\r\n                                <\/button>\r\n                            <\/div>\r\n                            <pre class=\"w-100 h-100 m-0 line-numbers language-Python\">\r\n                                <code id=\"code_0_content\" class=\"language-Python\">\r\n\r\n                                    import pika  \r\nimport requests\r\n\r\n# Configuration\r\nDOMAIN = &#039;example.com&#039;  \r\nMAILGUN_API_KEY = &#039;YOUR_MAILGUN_API_KEY&#039;  \r\nRABBITMQ_HOST = &#039;localhost&#039;\r\n\r\nconnection = pika.BlockingConnection(  \r\n    pika.ConnectionParameters(host=RABBITMQ_HOST)\r\n)\r\nchannel = connection.channel()  \r\nchannel.queue_declare(queue=&#039;welcome_queue&#039;, durable=True)\r\n\r\nclass Error(Exception):  \r\n    pass\r\n\r\nclass MailgunError(Error):  \r\n    def __init__(self, message):\r\n        self.message = message\r\n\r\ndef send_welcome_message(ch, method, properties, body):  \r\n    address = body.decode(&#039;UTF-8&#039;)\r\n    print(&quot;Sending welcome email to {}&quot;.format(address))\r\n    res = requests.post(\r\n        &quot;https:\/\/api.mailgun.net\/v3\/{}\/messages&quot;.format(DOMAIN),\r\n        auth=(&quot;api&quot;, MAILGUN_API_KEY),\r\n        data={&quot;from&quot;: &quot;Flaskr &quot;.format(DOMAIN),\r\n              &quot;to&quot;: [address],\r\n              &quot;subject&quot;: &quot;Welcome to Flaskr!&quot;,\r\n              &quot;text&quot;: &quot;Welcome to Flaskr, your account is now active!&quot;}\r\n    )\r\n    ch.basic_ack(delivery_tag=method.delivery_tag)\r\n    if res.status_code != 200:\r\n        # Something terrible happened :-O\r\n        raise MailgunError(&quot;{}-{}&quot;.format(res.status_code, res.reason))\r\n\r\nchannel.basic_consume(send_welcome_message, queue=&#039;welcome_queue&#039;)  \r\nchannel.start_consuming()  \r\n                                <\/code>\r\n                            <\/pre>\r\n                        <\/div>\r\n                    <\/div>\r\n                                    <\/div>\r\n    <\/div>\r\n\n\n\n<p class=\"wp-block-paragraph\">\u00a1Ya casi hemos terminado! Hemos desvinculado con \u00e9xito el env\u00edo de nuestro email de bienvenida del servicio web. Ahora lo \u00fanico que falta es que volvamos a intentar enviar el email de bienvenida en caso de que falle el env\u00edo por alg\u00fan motivo. Una forma inteligente de a\u00f1adir una l\u00f3gica de reintento a tu aplicaci\u00f3n es utilizar una cola de mensajes muertos (dead letter queue).<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">A\u00f1adiremos una segunda cola, \u201cretry_queue\u201d, que usaremos para colocar temporalmente un mensaje si nos encontramos con un error de env\u00edo del email. Los mensajes de la cola de reintento tendr\u00e1n una fecha de caducidad en el futuro. Configuraremos RabbitMQ de tal forma que cuando un mensaje caduque volver\u00e1 a nuestra cola de bienvenida para que un worker lo recoja e intente enviar el email de nuevo:<\/p>\n\n\n    <div data-content-type=\"longform\" class=\"code-snippet longform-spacings rounded-lg overflow-hidden shadow \" data-count=\"1\">\r\n        <ul class=\"nav nav-buttons code-snippet__tabs longform-except position-relative d-flex gap-2 flex-wrap p-3\" role=\"tablist\">\r\n\r\n                            \r\n                    \r\n                        <li class=\"nav-item\" role=\"presentation\">\r\n                            <button class=\"nav-link active\" data-bs-toggle=\"tab\" data-bs-target=\"#code_0\" type=\"button\" role=\"tab\" aria-controls=\"code_0\" aria-selected=\"true\">\r\n                                Python                            <\/button>\r\n                        <\/li>\r\n\r\n                    \r\n                            \r\n        <\/ul>\r\n        <div class=\"code-snippet__tab-content tab-content\">\r\n\r\n                            \r\n                    <div class=\"tab-pane show active\" id=\"code_0\" role=\"tabpanel\" aria-labelledby=\"code_0\">\r\n                        <div class=\"code-snippet__code-wrapper\">\r\n                            <div class=\"nav nav-buttons code-snippet__copy-wrapper\">\r\n                                <button type=\"button\" class=\"nav-link code-snippet__copy\" data-clipboard-target=\"#code_0_content\" data-clipboard-label=\"Copia al portapapeles\" data-clipboard-success-label=\"\u00a1Copiado!\" data-clipboard-error-label=\"No se ha podido copiar\" data-tooltip=\"Copia al portapapeles\" data-tooltip-placement=\"left\" role=\"tooltip\" aria-label=\"Copia al portapapeles\">\r\n                                    <svg class=\"code-snippet__copy-icon code-snippet__copy-icon--default\" width=\"24\" height=\"24\" aria-hidden=\"true\" data-url=\"https:\/\/www.mailgun.com\/wp-content\/plugins\/sinch-core\/assets\/icons\/sinch\/file-stack.svg\"><\/svg>\r\n                                    <svg class=\"code-snippet__copy-icon code-snippet__copy-icon--success\" width=\"24\" height=\"24\" aria-hidden=\"true\" data-url=\"https:\/\/www.mailgun.com\/wp-content\/plugins\/sinch-core\/assets\/icons\/sinch\/badge-check.svg\"><\/svg>\r\n                                <\/button>\r\n                            <\/div>\r\n                            <pre class=\"w-100 h-100 m-0 line-numbers language-Python\">\r\n                                <code id=\"code_0_content\" class=\"language-Python\">\r\n\r\n                                    retry_channel = connection.channel()  \r\nretry_channel.queue_declare(  \r\n    queue=&#039;retry_queue&#039;,\r\n    durable=True,\r\n    arguments={\r\n        &#039;x-message-ttl&#039;: RETRY_DELAY_MS,\r\n        &#039;x-dead-letter-exchange&#039;: &#039;amq.direct&#039;,\r\n        &#039;x-dead-letter-routing-key&#039;: &#039;welcome_queue&#039;\r\n    }\r\n)\r\n\r\ndef send_welcome_message(ch, method, properties, body):  \r\n    address = body.decode(&#039;UTF-8&#039;)\r\n    print(&quot;Sending welcome email to {}&quot;.format(address))\r\n    res = requests.post(\r\n        &quot;https:\/\/api.mailgun.net\/v3\/{}\/messages&quot;.format(DOMAIN),\r\n        auth=(&quot;api&quot;, MAILGUN_API_KEY),\r\n        data={&quot;from&quot;: &quot;Flaskr &quot;.format(DOMAIN),\r\n              &quot;to&quot;: [address],\r\n              &quot;subject&quot;: &quot;Welcome to Flaskr!&quot;,\r\n              &quot;text&quot;: &quot;Welcome to Flaskr, your account is now active!&quot;}\r\n    )\r\n    ch.basic_ack(delivery_tag=method.delivery_tag)\r\n    if res.status_code != 200:\r\n        print(&quot;Error sending to {}. {} {}. Retrying...&quot;.format(\r\n            address, res.status_code, res.reason\r\n        ))\r\n        retry_channel.basic_publish(\r\n            exchange=&#039;&#039;,\r\n            routing_key=&#039;retry_queue&#039;,\r\n            body=address,\r\n            properties=pika.BasicProperties(\r\n                delivery_mode=_DELIVERY_MODE_PERSISTENT\r\n            )\r\n        )\r\n                                <\/code>\r\n                            <\/pre>\r\n                        <\/div>\r\n                    <\/div>\r\n                                    <\/div>\r\n    <\/div>\r\n\n\n\n<p class=\"wp-block-paragraph\">\u00a1Y ya est\u00e1! Hemos introducido con \u00e9xito el env\u00edo as\u00edncrono en nuestra aplicaci\u00f3n utilizando RabbitMQ. Para descargar el repositorio completo del c\u00f3digo fuente con el ejemplo pr\u00e1ctico, echa un vistazo a\u00a0<a href=\"https:\/\/github.com\/dmend\/mg-async-flaskr\" target=\"_tabs\" rel=\"noopener noreferrer\">mi repo de GitHub<\/a>.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Recibe m\u00e1s gu\u00edas como esta suscribi\u00e9ndote al blog. Recibir\u00e1s una actualizaci\u00f3n cada semana con las \u00faltimas publicaciones del equipo de Mailgun. Y si a\u00fan no utilizas Mailgun para enviar, recibir y hacer un seguimiento de los emails de tu aplicaci\u00f3n, \u00a1deber\u00edas registrarte a continuaci\u00f3n!<\/p>\n\n\n\r\n    <aside data-content-type=\"longform\"  class=\"banner-block longform-spacings rounded-lg shadow-lg px-5 py-6 px-md-6 py-md-7 p-lg-7 bg-light\" data-theme=\"dark\" aria-labelledby=\"banner-block-block_c61f8b3b11c84693f555867e04a93ab8\">\r\n                    <p class=\"text-uppercase section-caption text-body-color\">\r\n                Reg\u00edstrate            <\/p>\r\n                            <p class=\"h4 text-accent fw-bold\" id=\"banner-block-block_c61f8b3b11c84693f555867e04a93ab8\">\r\n                Empezar es facil\u00edsimo. Y gratis.            <\/p>\r\n                            <div class=\"mb-0 text-body-color\">\r\n                                    <div class=\"content-body mb-0 text-body-color\">Descubre todo lo que puedes lograr con la mejor plataforma de entrega de emails del mundo.<\/div>\r\n                            <\/div>\r\n        \r\n        <div class=\"text-start mt-5\"><a href=\"https:\/\/signup.mailgun.com\/new\/signup\"  class=\"btn btn-secondary\" >Get started<\/a><\/div>\r\n    <\/aside>\r\n\r\n","protected":false},"excerpt":{"rendered":"<p>La gesti\u00f3n de colas de mensajes es una herramienta interesante que puede ayudarnos a crear sitios web o servicios web escalables. Una cola de mensajes permite a las aplicaciones comunicarse de forma as\u00edncrona mediante el env\u00edo de mensajes entre s\u00ed.<\/p>\n","protected":false},"author":13,"featured_media":4074,"menu_order":0,"template":"","meta":{"_acf_changed":true,"footnotes":""},"blog_category":[20],"class_list":["post-20397","blog","type-blog","status-publish","has-post-thumbnail","hentry","blog_category-email"],"acf":[],"yoast_head":"<!-- This site is optimized with the Yoast SEO plugin v28.4 - https:\/\/yoast.com\/product\/yoast-seo-wordpress\/ -->\n<title>C\u00f3mo configurar colas de mensajes para el env\u00edo as\u00edncrono - Transactional Email API Service For Developers | Mailgun<\/title>\n<meta name=\"description\" content=\"La gesti\u00f3n de colas de mensajes es una herramienta interesante que puede ayudarnos a crear sitios web o servicios web escalables, incluido el env\u00edo de emails.\" \/>\n<meta name=\"robots\" content=\"index, follow, max-snippet:-1, max-image-preview:large, max-video-preview:-1\" \/>\n<link rel=\"canonical\" href=\"https:\/\/www.mailgun.com\/es\/blog\/email\/configurar-cola-mensajes-envio-asincrono\/\" \/>\n<meta property=\"og:locale\" content=\"es_ES\" \/>\n<meta property=\"og:type\" content=\"article\" \/>\n<meta property=\"og:title\" content=\"C\u00f3mo configurar colas de mensajes para el env\u00edo as\u00edncrono - Transactional Email API Service For Developers | Mailgun\" \/>\n<meta property=\"og:description\" content=\"La gesti\u00f3n de colas de mensajes es una herramienta interesante que puede ayudarnos a crear sitios web o servicios web escalables, incluido el env\u00edo de emails.\" \/>\n<meta property=\"og:url\" content=\"https:\/\/www.mailgun.com\/es\/blog\/email\/configurar-cola-mensajes-envio-asincrono\/\" \/>\n<meta property=\"og:site_name\" content=\"Transactional Email API Service For Developers | Mailgun\" \/>\n<meta property=\"og:image\" content=\"https:\/\/www.mailgun.com\/wp-content\/uploads\/2025\/07\/MG-Blog-Email.png\" \/>\n\t<meta property=\"og:image:width\" content=\"720\" \/>\n\t<meta property=\"og:image:height\" content=\"448\" \/>\n\t<meta property=\"og:image:type\" content=\"image\/png\" \/>\n<meta name=\"twitter:card\" content=\"summary_large_image\" \/>\n<meta name=\"twitter:label1\" content=\"Est. reading time\" \/>\n\t<meta name=\"twitter:data1\" content=\"3 minutos\" \/>\n<script type=\"application\/ld+json\" class=\"yoast-schema-graph\">{\"@context\":\"https:\\\/\\\/schema.org\",\"@graph\":[{\"@type\":\"WebPage\",\"@id\":\"https:\\\/\\\/www.mailgun.com\\\/es\\\/blog\\\/email\\\/configurar-cola-mensajes-envio-asincrono\\\/\",\"url\":\"https:\\\/\\\/www.mailgun.com\\\/es\\\/blog\\\/email\\\/configurar-cola-mensajes-envio-asincrono\\\/\",\"name\":\"C\u00f3mo configurar colas de mensajes para el env\u00edo as\u00edncrono - Transactional Email API Service For Developers | Mailgun\",\"isPartOf\":{\"@id\":\"https:\\\/\\\/www.mailgun.com\\\/es\\\/#website\"},\"primaryImageOfPage\":{\"@id\":\"https:\\\/\\\/www.mailgun.com\\\/es\\\/blog\\\/email\\\/configurar-cola-mensajes-envio-asincrono\\\/#primaryimage\"},\"image\":{\"@id\":\"https:\\\/\\\/www.mailgun.com\\\/es\\\/blog\\\/email\\\/configurar-cola-mensajes-envio-asincrono\\\/#primaryimage\"},\"thumbnailUrl\":\"https:\\\/\\\/www.mailgun.com\\\/wp-content\\\/uploads\\\/2025\\\/07\\\/MG-Blog-Email.png\",\"datePublished\":\"2026-09-14T23:34:31+00:00\",\"description\":\"La gesti\u00f3n de colas de mensajes es una herramienta interesante que puede ayudarnos a crear sitios web o servicios web escalables, incluido el env\u00edo de emails.\",\"breadcrumb\":{\"@id\":\"https:\\\/\\\/www.mailgun.com\\\/es\\\/blog\\\/email\\\/configurar-cola-mensajes-envio-asincrono\\\/#breadcrumb\"},\"inLanguage\":\"es\",\"potentialAction\":[{\"@type\":\"ReadAction\",\"target\":[\"https:\\\/\\\/www.mailgun.com\\\/es\\\/blog\\\/email\\\/configurar-cola-mensajes-envio-asincrono\\\/\"]}]},{\"@type\":\"ImageObject\",\"inLanguage\":\"es\",\"@id\":\"https:\\\/\\\/www.mailgun.com\\\/es\\\/blog\\\/email\\\/configurar-cola-mensajes-envio-asincrono\\\/#primaryimage\",\"url\":\"https:\\\/\\\/www.mailgun.com\\\/wp-content\\\/uploads\\\/2025\\\/07\\\/MG-Blog-Email.png\",\"contentUrl\":\"https:\\\/\\\/www.mailgun.com\\\/wp-content\\\/uploads\\\/2025\\\/07\\\/MG-Blog-Email.png\",\"width\":720,\"height\":448},{\"@type\":\"BreadcrumbList\",\"@id\":\"https:\\\/\\\/www.mailgun.com\\\/es\\\/blog\\\/email\\\/configurar-cola-mensajes-envio-asincrono\\\/#breadcrumb\",\"itemListElement\":[{\"@type\":\"ListItem\",\"position\":1,\"name\":\"Home\",\"item\":\"https:\\\/\\\/www.mailgun.com\\\/es\\\/\"},{\"@type\":\"ListItem\",\"position\":2,\"name\":\"Blog\",\"item\":\"https:\\\/\\\/www.mailgun.com\\\/es\\\/blog\\\/\"},{\"@type\":\"ListItem\",\"position\":3,\"name\":\"C\u00f3mo configurar colas de mensajes para el env\u00edo as\u00edncrono\"}]},{\"@type\":\"WebSite\",\"@id\":\"https:\\\/\\\/www.mailgun.com\\\/es\\\/#website\",\"url\":\"https:\\\/\\\/www.mailgun.com\\\/es\\\/\",\"name\":\"Transactional Email API Service For Developers | Mailgun\",\"description\":\"Potentes API de email transaccional que te permiten enviar, recibir y hacer seguimiento de emails, creadas pensando en los desarrolladores. \u00a1Descubre m\u00e1s!\",\"publisher\":{\"@id\":\"https:\\\/\\\/www.mailgun.com\\\/es\\\/#organization\"},\"potentialAction\":[{\"@type\":\"SearchAction\",\"target\":{\"@type\":\"EntryPoint\",\"urlTemplate\":\"https:\\\/\\\/www.mailgun.com\\\/es\\\/?s={search_term_string}\"},\"query-input\":{\"@type\":\"PropertyValueSpecification\",\"valueRequired\":true,\"valueName\":\"search_term_string\"}}],\"inLanguage\":\"es\"},{\"@type\":\"Organization\",\"@id\":\"https:\\\/\\\/www.mailgun.com\\\/es\\\/#organization\",\"name\":\"Transactional Email API Service For Developers | Mailgun\",\"url\":\"https:\\\/\\\/www.mailgun.com\\\/es\\\/\",\"logo\":{\"@type\":\"ImageObject\",\"inLanguage\":\"es\",\"@id\":\"https:\\\/\\\/www.mailgun.com\\\/es\\\/#\\\/schema\\\/logo\\\/image\\\/\",\"url\":\"https:\\\/\\\/www.mailgun.com\\\/wp-content\\\/uploads\\\/2025\\\/06\\\/cropped-android-chrome-512x512-1.png\",\"contentUrl\":\"https:\\\/\\\/www.mailgun.com\\\/wp-content\\\/uploads\\\/2025\\\/06\\\/cropped-android-chrome-512x512-1.png\",\"width\":512,\"height\":512,\"caption\":\"Transactional Email API Service For Developers | Mailgun\"},\"image\":{\"@id\":\"https:\\\/\\\/www.mailgun.com\\\/es\\\/#\\\/schema\\\/logo\\\/image\\\/\"}}]}<\/script>\n<!-- \/ Yoast SEO plugin. -->","yoast_head_json":{"title":"C\u00f3mo configurar colas de mensajes para el env\u00edo as\u00edncrono - Transactional Email API Service For Developers | Mailgun","description":"La gesti\u00f3n de colas de mensajes es una herramienta interesante que puede ayudarnos a crear sitios web o servicios web escalables, incluido el env\u00edo de emails.","robots":{"index":"index","follow":"follow","max-snippet":"max-snippet:-1","max-image-preview":"max-image-preview:large","max-video-preview":"max-video-preview:-1"},"canonical":"https:\/\/www.mailgun.com\/es\/blog\/email\/configurar-cola-mensajes-envio-asincrono\/","og_locale":"es_ES","og_type":"article","og_title":"C\u00f3mo configurar colas de mensajes para el env\u00edo as\u00edncrono - Transactional Email API Service For Developers | Mailgun","og_description":"La gesti\u00f3n de colas de mensajes es una herramienta interesante que puede ayudarnos a crear sitios web o servicios web escalables, incluido el env\u00edo de emails.","og_url":"https:\/\/www.mailgun.com\/es\/blog\/email\/configurar-cola-mensajes-envio-asincrono\/","og_site_name":"Transactional Email API Service For Developers | Mailgun","og_image":[{"width":720,"height":448,"url":"https:\/\/www.mailgun.com\/wp-content\/uploads\/2025\/07\/MG-Blog-Email.png","type":"image\/png"}],"twitter_card":"summary_large_image","twitter_misc":{"Est. reading time":"3 minutos"},"schema":{"@context":"https:\/\/schema.org","@graph":[{"@type":"WebPage","@id":"https:\/\/www.mailgun.com\/es\/blog\/email\/configurar-cola-mensajes-envio-asincrono\/","url":"https:\/\/www.mailgun.com\/es\/blog\/email\/configurar-cola-mensajes-envio-asincrono\/","name":"C\u00f3mo configurar colas de mensajes para el env\u00edo as\u00edncrono - Transactional Email API Service For Developers | Mailgun","isPartOf":{"@id":"https:\/\/www.mailgun.com\/es\/#website"},"primaryImageOfPage":{"@id":"https:\/\/www.mailgun.com\/es\/blog\/email\/configurar-cola-mensajes-envio-asincrono\/#primaryimage"},"image":{"@id":"https:\/\/www.mailgun.com\/es\/blog\/email\/configurar-cola-mensajes-envio-asincrono\/#primaryimage"},"thumbnailUrl":"https:\/\/www.mailgun.com\/wp-content\/uploads\/2025\/07\/MG-Blog-Email.png","datePublished":"2026-09-14T23:34:31+00:00","description":"La gesti\u00f3n de colas de mensajes es una herramienta interesante que puede ayudarnos a crear sitios web o servicios web escalables, incluido el env\u00edo de emails.","breadcrumb":{"@id":"https:\/\/www.mailgun.com\/es\/blog\/email\/configurar-cola-mensajes-envio-asincrono\/#breadcrumb"},"inLanguage":"es","potentialAction":[{"@type":"ReadAction","target":["https:\/\/www.mailgun.com\/es\/blog\/email\/configurar-cola-mensajes-envio-asincrono\/"]}]},{"@type":"ImageObject","inLanguage":"es","@id":"https:\/\/www.mailgun.com\/es\/blog\/email\/configurar-cola-mensajes-envio-asincrono\/#primaryimage","url":"https:\/\/www.mailgun.com\/wp-content\/uploads\/2025\/07\/MG-Blog-Email.png","contentUrl":"https:\/\/www.mailgun.com\/wp-content\/uploads\/2025\/07\/MG-Blog-Email.png","width":720,"height":448},{"@type":"BreadcrumbList","@id":"https:\/\/www.mailgun.com\/es\/blog\/email\/configurar-cola-mensajes-envio-asincrono\/#breadcrumb","itemListElement":[{"@type":"ListItem","position":1,"name":"Home","item":"https:\/\/www.mailgun.com\/es\/"},{"@type":"ListItem","position":2,"name":"Blog","item":"https:\/\/www.mailgun.com\/es\/blog\/"},{"@type":"ListItem","position":3,"name":"C\u00f3mo configurar colas de mensajes para el env\u00edo as\u00edncrono"}]},{"@type":"WebSite","@id":"https:\/\/www.mailgun.com\/es\/#website","url":"https:\/\/www.mailgun.com\/es\/","name":"Transactional Email API Service For Developers | Mailgun","description":"Potentes API de email transaccional que te permiten enviar, recibir y hacer seguimiento de emails, creadas pensando en los desarrolladores. \u00a1Descubre m\u00e1s!","publisher":{"@id":"https:\/\/www.mailgun.com\/es\/#organization"},"potentialAction":[{"@type":"SearchAction","target":{"@type":"EntryPoint","urlTemplate":"https:\/\/www.mailgun.com\/es\/?s={search_term_string}"},"query-input":{"@type":"PropertyValueSpecification","valueRequired":true,"valueName":"search_term_string"}}],"inLanguage":"es"},{"@type":"Organization","@id":"https:\/\/www.mailgun.com\/es\/#organization","name":"Transactional Email API Service For Developers | Mailgun","url":"https:\/\/www.mailgun.com\/es\/","logo":{"@type":"ImageObject","inLanguage":"es","@id":"https:\/\/www.mailgun.com\/es\/#\/schema\/logo\/image\/","url":"https:\/\/www.mailgun.com\/wp-content\/uploads\/2025\/06\/cropped-android-chrome-512x512-1.png","contentUrl":"https:\/\/www.mailgun.com\/wp-content\/uploads\/2025\/06\/cropped-android-chrome-512x512-1.png","width":512,"height":512,"caption":"Transactional Email API Service For Developers | Mailgun"},"image":{"@id":"https:\/\/www.mailgun.com\/es\/#\/schema\/logo\/image\/"}}]}},"_links":{"self":[{"href":"https:\/\/www.mailgun.com\/es\/wp-json\/wp\/v2\/blog\/20397","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/www.mailgun.com\/es\/wp-json\/wp\/v2\/blog"}],"about":[{"href":"https:\/\/www.mailgun.com\/es\/wp-json\/wp\/v2\/types\/blog"}],"author":[{"embeddable":true,"href":"https:\/\/www.mailgun.com\/es\/wp-json\/wp\/v2\/users\/13"}],"version-history":[{"count":0,"href":"https:\/\/www.mailgun.com\/es\/wp-json\/wp\/v2\/blog\/20397\/revisions"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/www.mailgun.com\/es\/wp-json\/wp\/v2\/media\/4074"}],"wp:attachment":[{"href":"https:\/\/www.mailgun.com\/es\/wp-json\/wp\/v2\/media?parent=20397"}],"wp:term":[{"taxonomy":"blog_category","embeddable":true,"href":"https:\/\/www.mailgun.com\/es\/wp-json\/wp\/v2\/blog_category?post=20397"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}