Publi

Enviar e-mails con adjuntos desde la terminal con sendmail [Bash script]

En varias ocasiones, he necesitado enviar un e-mail a un compañero de trabajo (o a mí mismo) con información recién extraída de un servidor (por ejemplo un CSV de base de datos o información subida desde la web) y lo que he hecho al final ha sido bajármelo por SSH y una vez en mi ordenador he enviado el archivo donde ha sido necesario. Si eres como yo, que siempre tengo una sesión SSH abierta en mi servidor, ganarás un par de minutos con este script.

El siguiente script envía un correo electrónico utilizando sendmail. sendmail no es difícil, simplemente tenemos que escribir como entrada del correo las cabeceras necesarias y el mensaje, aunque podemos echar unos minutos hasta que se puede enviar correctamente el mensaje.
El problema con las cabeceras viene cuando tenemos que enviar archivos adjuntos, ya que las cabeceras que tenemos que enviar son un poco más complejas, y luego tenemos que codificar el archivo para que encaje en un e-mail y es algo que a mano resulta muy pesado.

Pues nada, si salvamos esto como gemail.sh sólo tenemos que hacer lo siguiente:

$ email.sh destino@servidor.com «Asunto del mensaje» «Hola mundo! Te mando un mensaje»

para enviar un mensaje normal, si queremos enviar adjuntos:

$ email.sh destino@servidor.com «Asunto del mensaje» «Hola mundo! Te mando un mensaje» fichero1 fichero2

siempre y cuando existan los archivos, la cosa irá bien, aunque también podemos insertar cabeceras nuevas en el correo, por ejemplo From (para especificar el remitente), CC y BCC (para copias) y Reply-to (para responder a esta dirección), etc. de la siguiente manera:

$ email.sh destino@servidor.com «Asunto del mensaje» «Hola mundo! Te mando un mensaje» «From: Yo mismo » «CC: un_amigo@direccion.com» fichero1 fichero2…

Siempre y cuando tengamos sendmail configurado, todos los e-mails se enviarán. Si algún e-mail no ha salido, podemos ver en /var/log/mail.log y /var/log/mail.err qué ha pasado con el envío, ya que sendmail se limita a encolar los mensajes, que ya se podrán enviar con el método que tengamos configurado (postfix, nullailer, etc)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
#!/bin/bash

# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.

# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
# GNU General Public License for more details.

# You should have received a copy of the GNU General Public License
# along with this program.  If not, see <http://www.gnu.org/licenses/>.

# gemail.sh  Copyright (C) 2014  Gaspar Fernández <gaspar.fernandez@totaki.com>

# This bash script will help you to use sendmail allowing us to send e-mails from
# the terminal in a friendly way just say destination, subject and body in the command
# arguments. It allows us also to send mail attachments with local files and allows you
# to use internal sendmail application or connection to a SMTP server.
#
# I find it interesting when using remotely a server with SSH and I must send a file
# located in it to someone. I wrote this little script to send the file directly to
# the destination.

# Changelog:
# - 20160902: Fixed bad python indentation (after yesterday's re-indentation)
# - 20160901: Fix selecting SMTP user
#             Fix when sending mails through cron jobs (again) this time,
#             when sending from scripts ran in cron jobs. /dev/stdin is
#             present in some conditions but with no data.
#             Indentation fix
# - 20160706: Several new CLI options.
# - 20160705: Added SMTP support with tiny python script
# - 20160703: Fixes adding headers and autoheaders
# - 20160415: Fix sending mails through cron job. Must check permissions over /dev/stdin
# - 20150216: Allow body to be read from stdin
# - 20150210: Bug fix separate recipient and non-recipient headers (for some reason some
#             mailers didn't do it right when they are mixed.
# - 20150210: Added SENDMAIL_BASIC_ARGS to call sendmail -t and allow more recipients
# - 20150113: Bug fix (sendmail with no arguments)
# - 20141212: Preview mode and additional sendmail find
# - 20141211: Removed extra \n when no extra headers
# - 20141208: Allows us to send many attachments
# - 20141206: Code clean up
# - 20141129: Initial idea of the script and wrote basic functionality

# To do:
#  - Doc and examples !!!

VERSION="0.8"
#MAIL_BOUNDARY="m41lb0und4ry"       # We can randomize it later
MAIL_BOUNDARY=`cat /dev/urandom | tr -dc 'a-zA-Z0-9' | head -c 40`
SENDMAIL_COMMAND=`which sendmail`
# Read recipients from mail (to use CC and so)
SENDMAIL_BASIC_ARGS="-t"
SENDMAIL_COMMAND="";
SMTP_DEFAULT_SECURITY="starttls"
_MYNAME=$0

function showUsage()
{
    # We must extend this help to use headers and so
    if [ -n "$1" ]
    then
        echo "Sorry: $1"
        echo
    fi
    echo "gemail.sh Version $VERSION"
    echo "Sends e-mails from terminal the easy way. (https://github.com/gasparfm/gscripts)"
    echo
    echo "Use:"
    echo "  $_MYNAME [options] [destination] [subject] [body] [attachment1] [attachment2] ... [attachmentN]"
    echo
    echo "or:"
    echo
    echo "  $_MYNAME [options] [destination] [subject] [attachment1] [attachment2] ... [attachmentN] < bodyfile"
    echo
    echo "These are the supported options:"
    echo " -t, --to=destination     : Adds to recipient to the e-mail (if this option is"
    echo "                present you can dismiss [destination] argument)."
    echo " -f, --from=origin    : This is YOUR e-mail."
    echo " -s, --subject=subject    : The subject of your message. (if this option is "
    echo "                present you can dismiss [subject] argument)."
    echo " -b, --body=message   : This is yout message. (if this option is present,"
    echo "                you can dismiss [body] argument)."
    echo " -p, --preview        : Don't send the message, just preview the e-mail."
    echo " -h, --header=content : Adds new header to the e-mail. Allowed headers are:"
    echo "                From, CC, BCC, Reply-to, Date, Organization, "
    echo "                X-Mailer and Message-Id."
    echo " -a, --attach=file    : Attaches this file to the e-mail."
    echo " -e, --smtp=conn_str  : Gives SMTP server or connection string."
    echo "            This connection string can be: "
    echo "              * server hostname or IP"
    echo "              * user:password@server (if user or password has :"
    echo "                 or @ characters they may be escaped.)"
    echo " -u, --smtp-user=user : Sets SMTP server user."
    echo " -w, --smtp-pass=passwd   : Sets SMTP server password."
    echo " -n, --noautoheaders  : Disables gemail.sh automatic headers."
    echo
    echo "You can also insert some more headers after the attachments:"
    echo "  "From: me@email.ext" or "From: Me <me@myself.ext>" to specify my email"
    echo "  "CC: my@email.ext" or "CC: My friend <my@friend.ext>" for carbon copy"
    echo "  "BCC: my@email.ext" or "BCC: My friend <my@friend.ext>" for blind carbon copy"
    echo "  "Reply-to: another@email.com" for a new reply-to address";
    echo "  Another headers accepted: Date, Organization, X-Mailer, Message-Id"
    echo
    echo "You can use the keyword *preview* to print the command to be executed (if you have attached files the output can be large)"
    exit
}

function findSendmail()
{
    # Try to find again sendmail in extra paths not in $PATH
    EXTRAPATHS=("/usr/sbin/" "/sbin/" "/usr/local/sbin/" "$HOME/.local/bin/")

    for p in "${EXTRAPATHS[@]}";
    do
        if [ -x "${p}sendmail" ]
        then
            echo "${p}sendmail"
            return
        fi
    done
}

function test_py()
{
    if [ -z "$(which python)" ]
    then
        echo "Python not found"
        return;
    fi

    python <<EOF
try:
    import smtplib
except ImportError as er:
        print er
EOF

}

function pysmtp()
{
    TO="$1"
    while read line
    do
        echo "$line"
    done | python <(cat <<EOF
import smtplib
import sys
try:
    smtpObj = smtplib.SMTP('$SMTP_SERVER')
    if ('$SMTP_SECURITY' == 'starttls'):
        smtpObj.starttls()
    if ('$SMTP_USER'):
        smtpObj.login('$SMTP_USER', '$SMTP_PASS')
    message = sys.stdin.read()
    _from = message.find('From:')
    fromstr = 'root'
    if _from != -1:
        fromstr = message[_from+5:message.find('\n', _from)]
    smtpObj.sendmail(fromstr.strip(), '$_TO', message)
except Exception as e:
    print e
EOF

    )
}

function callsend()
{
    _TO="$1"
    _PREVIEW=$2
    if (( $_PREVIEW==1 ))
    then
        cat
    elif [ $SENDER = "sendmail" ]
    then
        if [ -z "$SENDMAIL_COMMAND" ];
        then
            echo "No sendmail found in your PATH. Make sure you have it!"
            exit 1;
        fi
        $SENDMAIL_COMMAND $SENDMAIL_BASIC_ARGS "$_TO"
    elif [ $SENDER = "smtp" ]
    then
        PYERR="$(test_py)"
        if [ -n "$PYERR" ]
        then
            echo "Python error: $PYERR"
            exit 1;
        fi
        RESPONSE="$(pysmtp "$TO")"
        if [ -n "$RESPONSE" ]
        then
            echo "Error sending via SMTP: $RESPONSE"
            return 1;
        fi
    fi
}

function add_attachment()
{
    ATTACH="$1"
    ATTACH_MIME=`file --mime-type -b "$ATTACH"`
    ATTACH_NAME=`basename "$ATTACH"`
    ATTACH_BASE64=`base64 "$ATTACH"`
    ATTACHMENTS="$ATTACHMENTS
--$MAIL_BOUNDARY
Content-Type: $ATTACH_MIME; name="
$ATTACH_NAME"
Content-Transfer-Encoding: base64
Content-Disposition: attachment; filename="
$ATTACH_NAME"

$ATTACH_BASE64"

}

function add_header()
{
    HEADERINFO="$1"
    OLDIFS=$IFS
    IFS=":"
    read -a HEADER <<< "$HEADERINFO"
    IFS=$OLDIFS
    case ${HEADER[0]} in
        # Separating headers for some mail systems
        "From" | "Reply-to" | "CC" | "BCC" )
            if [ "${HEADER[0]}" = "From" ] || [ "${HEADER[0]}" = "Reply-to" ]
            then
                RECIPIENTS="$(echo -e "$RECIPIENTS" | grep -v "${HEADER[0]}:")"
            fi

            if [ -z "$RECIPIENTS" ]
            then
                RECIPIENTS=$HEADERINFO
            else
                RECIPIENTS="`echo -e "$RECIPIENTS""\n""$HEADERINFO"`"
            fi
            ;;
        "Date" | "X-Mailer" | "Organization" | "Message-Id" )
            MOREHEADERS="$(echo -e "$MOREHEADERS" | grep -v "${HEADER[0]}:")"
            if [ -z "$MOREHEADERS" ]
            then
                MOREHEADERS=$HEADERINFO
            else
                MOREHEADERS="`echo -e "$MOREHEADERS""\n""$HEADERINFO"`"
            fi
            ;;
        "preview")
            PREVIEW=1
            ;;
        *)
            showUsage "Attachment $HEADERINFO not found"
    esac
}

function add_auto_headers()
{
    if [ "$AUTOHEADERS" = "yes" ]
    then
        if [ -z "$(grep "From:" <<< $RECIPIENTS)" ]
        then
            add_header "From: $(echo `whoami`@`hostname`)"
        fi

        if [ -z "$(grep "Date: " <<< $MOREHEADERS)" ]
        then
            add_header "Date: $(date -R) ($(date +%Z))"
        fi

        if [ -z "$(grep "Message-Id: " <<< $MOREHEADERS)" ]
        then
            _FROM=$(grep "From:" <<< $RECIPIENTS)
            add_header "Message-Id: <"$(uuidgen | awk -F'-' -v date=$(date +%Y%m%d%H%M%S) -v at=$(echo $_FROM | cut -d'@' -f2) '{print $1$2"."date"."$3$4"@"at}')">"
        fi
        if [ -z "$(grep "X-Mailer: " <<< $MOREHEADERS)" ]
        then
            add_header "X-Mailer: gemail.sh Ver. $VERSION"
        fi
    fi
}

function smtp_settings()
{
    STS="$1"

    OLDIFS=$IFS
    IFS=$(echo -e "\n")
    while read user
    do
        read pass
        read server
        break
    done <<< $(sed -r 's/([^\:\@]*(\\:[^\:\@]*)*):([^\@]*(\\@[^\:\@]*)*)@([^\/\:]*)/\1\n\3\n\5/' <<< "$STS");
    if [ -z "$user" ]
    then
        showUsage "Wrong SMTP server string: "$STS""
    fi
    SENDER="smtp"
    if [ -z "$pass" ] && [ -z "$server" ]
    then
        # We only have server
        SMTP_SERVER="$user"
    else
        SMTP_SERVER="$server"
        SMTP_USER="$user"
        SMTP_PASS="$pass"
    fi
    SMTP_SECURITY=$SMTP_DEFAULT_SECURITY
}

# Fill missing headers automatically
AUTOHEADERS="yes"
ATTACHMENTS=""
MOREHEADERS=""
RECIPIENTS=""

# By default, no PREVIEW
PREVIEW=0

# By default, sent by sendmail
SENDER="sendmail"

# Parse input arguments
ARGS=$(getopt -q -o "t:f:s:b:ph:a:e:u:w:n" -l "to:,from:,subject:,body:,preview,header:,attach:,smtp:,smtp-user:,smtp-pass:,noautoheaders" -n "gemail.sh" -- "$@");
if [ $? -ne 0 ];
then
    showUsage "Error parsing arguments"
fi

eval set -- "$ARGS";

while [ $# -gt 0 ]; do
    case "$1" in
        -t|--to)
            TO="$2"
            shift;
            ;;
        -f|--from)
            add_header "From: $2"
            shift;
            ;;
        -s|--subject)
            SUBJECT="$2"
            shift;
            ;;
        -b|--body)
            BODY="$3"
            shift;
            ;;
        -p|--preview)
            PREVIEW=1
            ;;
        -h|--header)
            add_header "$2"
            shift;
            ;;
        -a|--attach)
            add_attachment "$2"
            shift;
            ;;
        -e|--smtp)
            smtp_settings "$2"
            shift;
            ;;
        -u|--smtp-user)
            SMTP_USER="$2"
            shift
            ;;
        -w|--smtp-pass)
            SMTP_PASS="$2"
            shift
            ;;

        -n|--noautoheaders)
            AUTOHEADERS="no"
            ;;
        --)
            shift;
            break;
            ;;
        *)
            echo "Unrecognised option "$1""
            showUsage
    esac
    shift;
done
if [ -n "$1" ] && [ -z "$TO" ]
then
    TO="$1"
    shift
fi

if [ -n "$1" ] && [ -z "$SUBJECT" ]
then
    SUBJECT="$1"
    shift
fi

# If we have data in /dev/stdin pick up the email body from /dev/stdin
# -t 0 : make sure stdin (fd=0) is not a terminal as this program is not
# interactive
if [ -r /dev/stdin ] && [ ! -t 0 ]
then
    BODY=$(cat /dev/stdin)
fi
# If we have no body yet, test the argument. In cron jobs /dev/stdin may
# be detected with no data.
if [ -n "$1" ] && [ -z "$BODY" ]
then
    BODY="$1"
    shift
fi

# Additional sendmail find if not in PATH
if [ -z "$SENDMAIL_COMMAND" ];
then
    SENDMAIL_COMMAND=`findSendmail`
fi

# Fill attachments and additional user headers
while [ $# -gt 0 ]
do
    ATTACH="$1"
    if [ ! -r "$ATTACH" ];
    then
        # Not an attachment, ok but it can be an additional header it will have : let's check it
        add_header "$ATTACH"
    else
        add_attachment "$ATTACH"
    fi
    shift
done

if [ -z "$TO" ]
then
    showUsage "No recipient found."
elif [ -z "$SUBJECT" ]
then
    showUsage "No subject found."
elif [ -z "$BODY" ]
then
    showUsage "No body found."
fi

# echo "TO: $TO"
# echo "SUBJECT: $SUBJECT"
# echo "BODY: $BODY"

add_auto_headers

# Send message
( echo "To: $TO";
    if [ -n "$RECIPIENTS" ]; then
        echo -e "$RECIPIENTS"
    fi
    echo "Subject: $SUBJECT";
    if [ -n "$MOREHEADERS" ]; then
        echo -e "$MOREHEADERS"
    fi
    echo "MIME-Version: 1.0";
    echo "Content-Type: multipart/mixed; boundary="$MAIL_BOUNDARY"";
    echo -e "\n"
    echo "--"$MAIL_BOUNDARY;
    echo "Content-Type: text/plain";
    echo -e "Content-Disposition: inline\n";
    echo "$BODY";
    echo -e "$ATTACHMENTS"
    echo "--"$MAIL_BOUNDARY"--") | callsend $TO $PREVIEW

RESULT=$?
if (( $RESULT==0 ))
then
    echo "Message sent successfully";
else
    echo "Could not send message"
fi

Este código lo encontráis también en mi Github.

Actualización 05/11/2016 : Se ha actualizado el código fuente, para copiar y pegar directamente. Estoy preparando también un post con ejemplos de uso muy ilustrativo que nos puede salvar la vida en más de una ocasión.

Foto: Esparta Palma (Flickr CC-by)

También podría interesarte....

There are 28 comments left Ir a comentario

  1. Pingback: Cómo crear milters en Python y configurar Postfix para filtrar correo – Poesía Binaria /

  2. Karter221 /
    Usando Google Chrome Google Chrome 119.0.0.0 en Windows Windows NT

    May possibly fairly recently up and running an important web log, the data one offer you on this web site contains given a hand to all of us substantially. Bless you designed for your current precious time & get the job done. UFABETแทงบอลบนมือถือที่ดีที่สุด

  3. Karter221 /
    Usando Google Chrome Google Chrome 119.0.0.0 en Windows Windows NT

    I assumed it is usually a preview to post in case others appeared to be having problems getting acquainted with nonetheless We’re a little bit hesitant merely i’m permitted to decide to put companies plus covers for listed here. UFABETราคาต่อรองบอลดีที่สุดในเอเชีย

  4. seooo servicesss /
    Usando Google Chrome Google Chrome 120.0.0.0 en Windows Windows NT

    Discover the ultimate karaoke experience in Daegu! Unleash your inner superstar at Daegu’s top karaoke spots, where modern technology meets traditional entertainment. Sing your heart out in stylish private rooms, equipped with the latest sound systems. Elevate your nightlife with Daegu Karaoke – the city’s rhythm awaits your unforgettable performance! 대구 가라오케

  5. yitzchak kerrigan /
    Usando Google Chrome Google Chrome 120.0.0.0 en Windows Windows NT

    Your content is nothing short of brilliant in many ways. I think this is engaging and eye-opening material. Thank you so much for caring about your content and your readers. 타이마사지

  6. yitzchak kerrigan /
    Usando Google Chrome Google Chrome 120.0.0.0 en Windows Windows NT

    Being Starter, I’m sure for life trying over the internet for the purpose of content pieces that might be from assistance to everybody. Regards. daftar indosport99

  7. ALEXENDER RAVI /
    Usando Google Chrome Google Chrome 120.0.0.0 en Windows Windows NT

    Discover the safest FX margin trading platforms with our expert guidance. Ensure the legality of your trades by choosing our recommended sites. Sign up seamlessly and invest with confidence.» fx마진거래

  8. seooo servicesss /
    Usando Google Chrome Google Chrome 120.0.0.0 en Windows Windows NT

    Pretty good post. I just stumbled upon your blog and wanted to say that I have really enjoyed reading your blog posts. Any way I’ll be subscribing to your feed and I hope you post again soon. Big thanks for the useful info. รวมทางเข้า ufabet

  9. seooo servicesss /
    Usando Google Chrome Google Chrome 120.0.0.0 en Windows Windows NT

    It is a great website.. The Design looks very good.. Keep working like that!. ติดต่อ ufabet

  10. MUZAMMIL SEO MUZAMMIL SEO /
    Usando Google Chrome Google Chrome 120.0.0.0 en Windows Windows NT

    I was reading some of your content on this website and I conceive this internet site is really informative ! Keep on putting up. 8us

  11. MUZAMMIL SEO MUZAMMIL SEO /
    Usando Google Chrome Google Chrome 120.0.0.0 en Windows Windows NT

    Great job for publishing such a beneficial web site. Your web log isn’t only useful but it is additionally really creative too. MGM 카지노

  12. seooo servicesss /
    Usando Google Chrome Google Chrome 120.0.0.0 en Windows Windows NT

    I really loved reading your blog. It was very well authored and easy to undertand. Unlike additional blogs I have read which are really not tht good. I also found your posts very interesting. In fact after reading, I had to go show it to my friend and he ejoyed it as well! UFABETโปรโมชั่นเดิมพันมากที่สุด

  13. seooo servicesss /
    Usando Google Chrome Google Chrome 120.0.0.0 en Windows Windows NT

    very interesting post.this is my first time visit here.i found so mmany interesting stuff in your blog especially its discussion..thanks for the post! สมัคร ufabet

  14. seooo servicesss /
    Usando Google Chrome Google Chrome 120.0.0.0 en Windows Windows NT

    i read a lot of stuff and i found that the way of writing to clearifing that exactly want to say was very good so i am impressed and ilike to come again in future.. ufabet เข้าสู่ระบบ ฝาก ถอน

  15. seooo servicesss /
    Usando Google Chrome Google Chrome 120.0.0.0 en Windows Windows NT

    Wow, excellent post. I’d like to draft like this too – taking time and real hard work to make a great article. This post has encouraged me to write some posts that I am going to write soon. 프리카지노

  16. MUZAMMIL SEO MUZAMMIL SEO /
    Usando Google Chrome Google Chrome 120.0.0.0 en Windows Windows NT

    Interesting topic for a blog. I have been searching the Internet for fun and came upon your website. Fabulous post. Thanks a ton for sharing your knowledge! It is great to see that some people still put in an effort into managing their websites. I’ll be sure to check back again real soon. 메이저사이트

  17. seooo servicesss /
    Usando Google Chrome Google Chrome 120.0.0.0 en Windows Windows NT

    I appreciate everything you have added to my knowledge base.Admiring the time and effort you put into your blog and detailed information you offer.Thanks. UFABETเว็บพนันบอลที่นิยม

  18. ghori92 /
    Usando Google Chrome Google Chrome 120.0.0.0 en Windows Windows NT

    thank you for your interesting infomation. UFABETสมัครเว็บแทงบอลออนไลน์รับยูสเซอร์ฟรี

  19. MUZAMMIL SEO MUZAMMIL SEO /
    Usando Google Chrome Google Chrome 120.0.0.0 en Windows Windows NT

    This is my first time i visit here. I found so many interesting stuff in your blog especially its discussion. From the tons of comments on your articles, I guess I am not the only one having all the enjoyment here keep up the good work 대구 밤문화

  20. jameels feerock /
    Usando Google Chrome Google Chrome 120.0.0.0 en Windows Windows NT

    I appreciate everything you have added to my knowledge base.Admiring the time and effort you put into your blog and detailed information you offer.Thanks. UFABETราคาต่อรองบอลไม่มีค่าน้ำ

  21. seooo servicesss /
    Usando Google Chrome Google Chrome 120.0.0.0 en Windows Windows NT

    Really unquie place, Thank you so much meant for posting The experience. Fantasticly penned report, anxieties most of folks given similar volume of material as you may, the online market place might be a a lot better put. Be sure to keep it up! UFABETสมัครแทงบอลคาสิโนออนไลน์

  22. MUZAMMIL SEO MUZAMMIL SEO /
    Usando Google Chrome Google Chrome 121.0.0.0 en Windows Windows NT

    I think this is a really good article. You make this information interesting and engaging. You give readers a lot to think about and I appreciate that kind of writing. 마포룸싸롱

  23. MUZAMMIL SEO MUZAMMIL SEO /
    Usando Google Chrome Google Chrome 121.0.0.0 en Windows Windows NT

    Divine Triumphs Await in Zeus Slot: Discover the joy of divine triumphs with Zeus Slot’s gampang menang design! Every spin holds the potential for legendary wins, taking you on an epic journey through the realms of Greek mythology. Brace yourself for epic victories! slot88

  24. MUZAMMIL SEO MUZAMMIL SEO /
    Usando Google Chrome Google Chrome 121.0.0.0 en Windows Windows NT

    I really impressed after read this because of some quality work and informative thoughts . I just wanna say thanks for the writer and wish you all the best for coming!. Dryer Vent Cleaning Maryland

  25. The Union Mike McKenna Green Jacket /
    Usando Google Chrome Google Chrome 121.0.0.0 en Windows Windows NT

    blog. I have read and thought about what you said. I have bookmarked it and I am looking forward to reading new articles. Keep up the good work!

  26. abdul moeez /
    Usando Google Chrome Google Chrome 121.0.0.0 en Windows Windows NT

    Weddings, event planning, and parties are the canvases of celebration, where every brushstroke of detail adds vibrancy to the portrait of joy. From the meticulous arrangements to the heartfelt exchanges, each moment is a masterpiece of love and togetherness. Here’s to crafting unforgettable experiences that paint our lives with happiness and cherished memories! WeddingThingz

  27. abdul moeez /
    Usando Google Chrome Google Chrome 121.0.0.0 en Windows Windows NT

    Being a mom is an incredible journey filled with love, laughter, and challenges. Prioritizing family health and wellness makes all the difference. From nutritious recipes to mindful activities, let’s empower each other to create a happy, healthy environment for our kids to thrive. Here’s to embracing the chaos with grace https://familyhw.com

  28. MUZAMMIL SEO MUZAMMIL SEO /
    Usando Google Chrome Google Chrome 122.0.0.0 en Windows Windows NT

    I love the way you write and share your niche! Very interesting and different! Keep it coming! chimney installation

Leave a Reply