تطبيقات بايثون - كيف تُرسل بريد إلكتروني مع مرفق في البايثون

تطبيقات بايثون – كيف تُرسل بريد إلكتروني مع مرفق في البايثون

تطبيقات بايثون عديدة ومتشعبة في أكثر من مجال، وذلك لما تتمتع به لغة البايثون من مزايا وخصائص تجعلها حلًا للعديد من المشاكل والعقبات. نُرحب بكم في هذا المقال الجديد من بايثونات والذي نتناول فيه أحد تطبيقات بايثون وهو كيفية التعامل مع مكتبة smtplib ومكتبة email المعياريتان في البايثون والتي تُساعدانا في ارسال بريد إلكتروني بخيارات متعددة.

مع نهاية هذا المقال ستكون عزيزي القارئ قادرٌ على تنفيذ أحد تطبيقات بايثون ومن خلاله تستطيع الإجابة على الأسئلة التالية:

  • كيف أُرسل بريد إلكتروني باستخدام smtplib ؟
  • كيف أُرسل بريد إلكتروني لأكثر من عنوان ؟
  • كيف أتعامل مع خيارات “نُسخة إلى” و “نُسخة مخفية” ؟
  • كيف أُضيف مُرفقات للبريد الإلكتروني باستخدام مكتبة email ؟

مكتبة smtblib

تقدم البايثون العديد من الخيارات في مكتباتها للتعامل مع البريد الإلكتروني. أشهر هذه المكتبات هي مكتبة smtplib المُضمنة تلقائيًا في البايثون. تعمل المكتبة على انشاء SMTP client session نتمكن من خلالها إرسال بريد إلكتروني لأي عنوان بريد إلكتروني في الإنترنت. يتم ذلك عبر استخدام البروتوكول الشهير SMTP protocol.

SMTP هي اختصار لـ Simple Mail Transfer Protocol. عند استخدام المكتبة، يتم إنشاء كائن من نوع الفئة SMTP يُمكن استخدامه فيما بعد في ارسال البريد الإلكتروني.

import smtplib

smtpObj = smtplib.SMTP( [host [, port [, local_hostname]]])

المعطيات التي يُمكن تمريرها للكائن المنشأ من فئة SMTP هي:

  • المُضيف host: هو عنوان IP الخاص بالخادم الذي يُشغل خدمة SMTP.
  • المنفذ port: وهو رقم المنفذ المستخدم في خادم SMTP والذي يتنصت من خلاله على طلبات الإرسال القادمة إليه. في حال أعددنا معطى host يجب علينا هنا تحديد رقم المنفذ والذي يكون بالعادة 25.
  • اسم المُضيف المحلي host_localname: في حالة استضافة خادم SMTP على جهازك المحلي، يُمكنك تمرير localhost لهذا المُعطى.

يحتوي الكائن المُنشأ من فئة SMTP على وظيفة sendmail وتستقبل ثلاثة معطيات رئيسية هي:

  1. البريد المُرسِل.
  2. البريد المُرسَل إليه.
  3. نص الرسالة.

كيف أُرسل بريد إلكتروني باستخدام smtplib ؟

قبل البدء باستخدام مكتبة smtplib لإرسال بريد إلكتروني، نحتاج إلى حساب بريد إلكتروني من أي خدمة بريد إلكتروني مثل GMAIL أو مثيلاتها. لهذا المقال سننشئ حساب بريد إلكتروني من خلال جوجل بالعنوان [email protected]، وسنحتاج أيضًا تفعيل خيار الوصول للتطبيقات الأقل أمانًا من الرابط التالي:

https://myaccount.google.com/lesssecureapps

تفعيل خيار الوصول لتطبيقات الأقل أمانًا
تفعيل خيار الوصول لتطبيقات الأقل أمانًا

عندما نريد أن نُرسل بريد إلكتروني باستخدام البايثون، علينا في البداية أن نتأكد من إعدادات الأمان الخاصة باتصال smtp. تجهيز إعدادات الأمان للإتصال ستحافظ على سرية البيانات التي يتم انتقالها في الإتصال.  سنستخدم لإضافة إعدادات الأمان وحدة ssl التي تُوفر آليات تجهيز الاتصال المُشفر. في البداية نستورد smtp و ssl:

import smtplib, ssl

بعد ذلك نُعرف المنفذ الذي سيتم الاتصال به في خادم smtp (منفذ smtp.gmail.com هو 465 للإتصال عبر ssl)، ثم نستدعي دالة create_default_context من وحدة ssl والتي تُرجع لنا كائن من نوع SSLContext. الكائن المُرجع SSLContext يتضمن إعدادت اتصال عبر بروتوكول SSL مُهيئة مُسبقًا، وسيتم استخدام هذا الكائن في تعريف المتغير server الذي يليه كما يلي:

port = 465 
context = ssl.create_default_context()
server = smtplib.SMTP_SSL("smtp.gmail.com", port, context=context)

بعد ذلك نُجهز المتغيرات العامة التي ستُمثل لنا بريد المُرسل وبريد المُرسل إليه ونص الرسالة وعنوانها:

sender_email = '[email protected]'
rec_email = '[email protected]'
subject = 'Greetings from Pythonat'
msg_body = 'Hi from Pythonat.com'
message = 'Subject: {}\n\n{}'.format(subject, msg_body)

قبل ارسال البريد الإلكتروني، لابد أن نقوم بعملية الاستيثاق authentication من خلال دالة login كما يلي:

password = input('Type your password and press enter: ')
server.login(sender_email, password)

الأن بعد أن أعددنا كافة البيانات اللازمة للبريد، وبعد أن أجرينا عملية الاستيثاق، يتبقى لنا ارسال البريد الإلكتروني والخروج من الاتصال:

server.sendmail(sender_email, rec_email, message)
server.quit()

تهانينا! لقد ارسلت بريدًا إلكترونيًا باستخدام مكتبة smtp في البايثون. الشيفرة البرمجية الكاملة كالتالي:

import smtplib, ssl

port = 465
context = ssl.create_default_context()
server = smtplib.SMTP_SSL('smtp.gmail.com', port, context=context)

sender_email = '[email protected]'
rec_email = '[email protected]'
subject = 'Greetings from Pythonat'
msg_body = 'Hi from Pythonat.com'
message = 'Subject: {}\n\n{}'.format(subject, msg_body)

password = input('Type your password and press enter: ')
server.login(sender_email, password)

server.sendmail(sender_email, rec_email, message)
server.quit()

تطبيقات بايثون – تحسين الشيفرة البرمجية

من الجميل أننا حققنا الهدف باستخدام 13 سطر برمجي (الأسطر الفارغة غير معدودة)، ولكن من الأفضل أن نُحسن الشيفرة البرمجية بحيث تكون مقروءة بشكل أفضل. سنحاول تقليل عدد الأسطر البرمجية وفصل بعض المعلومات التي يُمكن تخزينها في ملف خارجي بالإضافة إلى استخدام البرمجة كائنية التوجه.

اقرأ أيضًا: البرمجة الكائنية في بايثون

سنحفظ البريد الإلكتروني الذي سنستخدمه في الارسال واسم الخادم ورقم المنفذ في ملف خارجي منفصل باسم email.init وسيكون محتواه بالشكل التالي:

[smtp]
server = smtp.gmail.com
port = 465

[sender]
from = [email protected]

نُنشئ ملف بايثون جديد باسم sendBrain.py بحيث يحتوي على الشيفرة البرمجية التي ستعرف فئة باسم PythonatEmail وستتضمن هذه الفئة آلية إنشاء وارسال البريد الإلكتروني:

import smtplib, ssl, sys
from configparser import ConfigParser
from getpass import getpass

class PythonatEmail():
    def __init__(self, toAddress, subject, body):
        print('Configuring Pytonat email system...')
        self.configSMTB()
        self.subject = subject
        self.toAddress = toAddress
        self.body = body
        print('Enter your password please: ')
        self.password = getpass()

    def configSMTB(self):
        print('Configuring SMTP...')
        cfg = ConfigParser()
        cfg.read('email.init')
        self.server = cfg.get('smtp','server')
        self.port = cfg.get('smtp','port')
        self.sender = cfg.get('sender','from')

    def sendEmail(self):
        print('Sending Email...')
        message = 'Subject: {}\n\n{}'.format(self.subject, self.body)
        context = ssl.create_default_context()
        server = smtplib.SMTP_SSL(self.server, self.port, context=context)
        server.login(self.sender, self.password)
        server.sendmail(self.sender, self.toAddress, message)
        server.quit()
        print('Sending Email finished.')

كُل ما علينا فعله لإرسال البريد الإلكتروني هو استيراد وحدة sendBrain حتى نستطيع الوصول إلى فئة PythonatEmail وتعريف كائن من هذه الفئة واستدعاء دالة الإرسال بالطريقة التالية:

from sendBrain import PythonatEmail

subject = 'Hello From Pythonat'
body = '''Hi,
It is our honor to contact you and say Hello for you!
Pythonat Team.'''

email = PythonatEmail(toAddress='[email protected]', subject=subject, body=body)
email.sendEmail()

عند تنفيذ الشيفرة البرمجية السابقة، سيقوم مُفسر البايثون بطلب كلمة المرور وبعد ادخالها سيتم ارسال البريد الإلكتروني:

كيف ترسل بريد إلكتروني بالبايثون
كيف ترسل بريد إلكتروني بالبايثون

لاحظ معي أنه بعد أن قمنا بفصل المعلومات وترتيب الشيفرة البرمجية، استطعنا ارسال البريد باستخدام 5 أسطر برمجية فقط.

حتى تستطيع تجربة الشيفرة البرمجية السابقة بنفسك، لا تنسى تغيير الإعدادات في ملف email.init بحيث تضع في البريد الإلكتروني المُرسل وعنوان الخادم المُستخدم.

كيف أُرسل بريد إلكتروني لأكثر من عنوان ؟

حتى تستطيع إرسال البريد الإلكتروني، لن تُغير كثيرًا في الشيفرة البرمجية، فكُل ما عليك فعله هو وضع العناوين التي تُريد الإرسال لها في قائمة وتمرير هذه القائمة لدالة sendEmail كما يلي:

from sendBrain import PythonatEmail

subject = 'Hello From Pythonat'
body = '''Hi,
It is our honor to contact you and say Hello for you!
Pythonat Team.'''

emails = ['email1', 'email2', 'email3',...]
email = PythonatEmail(toAddress=emails, subject=subject, body=body)
email.sendEmail()

كيف أتعامل مع خيارات “نُسخة إلى” و “نُسخة مخفية” ؟

في الكثير من الأوقات نحتاج أن نُضيف نُسخة مخفية لعنوان ما أو نُسخة عادية عند إرسال البريد الإلكتروني. سنعمل على تغيير الشيفرة البرمجية في ملف sendBrain بحيث يُمكن لتعريف الفئة PythonatEmail أن يستوعب المتطلبات الجديدة:

import smtplib, ssl, sys
from configparser import ConfigParser
from getpass import getpass

class PythonatEmail():
    def __init__(self, toAddress, subject, body, cc=None, bcc=None):
        print('Configuring Pytonat email system...')
        self.configSMTB()
        self.subject = subject
        self.toAddress = toAddress
        self.body = body
        self.cc = cc
        self.bcc = bcc
        print('Enter your password please: ')
        self.password = getpass()

    def configSMTB(self):
        print('Configuring SMTP...')
        cfg = ConfigParser()
        cfg.read('email.init')
        self.server = cfg.get('smtp','server')
        self.port = cfg.get('smtp','port')
        self.sender = cfg.get('sender','from')

    def sendEmail(self):
        print('Sending Email...')
        message =  "\r\n".join((
                 "CC: %s" % self.cc,
                 "BCC: %s" % self.bcc,
                 "Subject: %s" % self.subject ,
                 "",
                 self.body
                 ))
        context = ssl.create_default_context()
        server = smtplib.SMTP_SSL(self.server, self.port, context=context)
        server.login(self.sender, self.password)
        server.sendmail(self.sender, self.toAddress, message)
        server.quit()
        print('Sending Email finished.')

نُلاحظ أننا عدلنا الدالة البانية للفئة PythonatEmail لكي تستقبل معلومات العناوين لكل من CC و BCC بالإضافة لتعديل الجزء الخاص بتكوين نص الرسالة في دالة sendEmail. سيكون البرنامج الرئيسي كما يلي:

from sendBrain import PythonatEmail

subject = 'Hello From Pythonat'
body = '''Hi Ibrahim,
It is our honor to contact you and say Hello for you!
Pythonat Team.'''

emails = ['email1', 'CC email2', 'BCC email3']
email = PythonatEmail(toAddress=emails, subject=subject, body=body,cc=[emails[1]],bcc=[emails[2]])
email.sendEmail()

كيف أُضيف مُرفقات للبريد الإلكتروني ؟

سنعمل الأن على ترتيب الشيفرة البرمجية بحيث تُصبح متكاملة ويُمكن من خلالها ارسال بريد إلكتروني يتضمن ملف مُرفق. تُقدم لنا وحدة email المعيارية في البايثون كُل ما نحتاجه لارسال بريد الكتروني مع مرفق. الشيفرة البرمجية المعدلة لملف sendBrain سيكون كالتالي:

import smtplib, ssl, sys
from configparser import ConfigParser
from getpass import getpass

from email import encoders
from email.mime.text import MIMEText
from email.mime.base import MIMEBase
from email.mime.multipart import MIMEMultipart
from email.utils import formatdate

class PythonatEmail():
    def __init__(self, toAddress, subject, body, cc=None, bcc=None):
        print('Configuring Pytonat email system...')
        self.configSMTB()
        self.subject = subject
        self.toAddress = toAddress
        self.body = body
        self.cc = cc
        self.bcc = bcc
        print('Enter your password please: ')
        self.password = getpass()

    def configSMTB(self):
        print('Configuring SMTP...')
        cfg = ConfigParser()
        cfg.read('email.init')
        self.server = cfg.get('smtp','server')
        self.port = cfg.get('smtp','port')
        self.sender = cfg.get('sender','from')

    def sendEmail(self, attachFile = None):
        print('Sending Email...')
        message = MIMEMultipart()
        message["From"] = self.sender
        message["Subject"] = self.subject
        message["Date"] = formatdate(localtime=True)
        message.attach( MIMEText(self.body) )

        message["To"] = self.toAddress
        message["cc"] = self.cc
        message["bcc"] = self.bcc
        if attachFile:
            try:
                header = 'Content-Disposition', 'attachment; filename="%s"' % attachFile
                attachment = MIMEBase('application', "octet-stream")
                with open(attachFile, "rb") as fh:
                    data = fh.read()
                attachment.set_payload(data)
                encoders.encode_base64(attachment)
                attachment.add_header(*header)
                message.attach(attachment)
            except IOError:
                errmsg = "Error opening attachment file %s" % file_to_attach
                print(errmsg)
                sys.exit(1)

        context = ssl.create_default_context()
        server = smtplib.SMTP_SSL(self.server, self.port, context=context)
        server.login(self.sender, self.password)
        emails = [self.toAddress, self.cc, self.bcc]
        server.sendmail(self.sender, emails, message.as_string())
        server.quit()
        print('Sending Email finished.')

والملف الرئيسي كالتالي:

from sendBrain import PythonatEmail

subject = 'Hello From Pythonat'
body = '''Hi Ibrahim,
It is our honor to contact you and say Hello for you!
Pythonat Team.'''

to = 'email1'
cc = 'email2'
bcc = 'email3'

email = PythonatEmail(toAddress=to, subject=subject, body=body,cc=cc,bcc=bcc)
email.sendEmail(attachFile='PythonatLogo.png')

لاحظ أننا اعتمدنا على وحدة email في تكوين نص الرسالة وارفاق الملف المرفق والذي هو عبارة عن صورة باسم PythonatLogo.png. حتى تعمل الشيفرة البرمجية بشكل سليم، لابد من وجود الصورة في نفس مسار العمل. لقد عدلنا الدالة sendEmail في ملف sendBrain بحيث يُمكن لها أن تستقبل معامل يُمثل اسم الملف المُرفق، وفي متن الدالة استخدمنا الفئة MIMEMultipart في تعريف كائن باسم messege والذي حددنا من خلاله تفاصيل البريد الالكتروني.

الجزء الخاص بإضافة الملف المُرفق يتضمن تعريف header وقراءة الملف على شكل بيانات ثنائية binary data ثم اضافة هذه البيانات كمُرفق من خلال دالة set_payload:

        if attachFile:
            try:
                header = 'Content-Disposition', 'attachment; filename="%s"' % attachFile
                attachment = MIMEBase('application', "octet-stream")
                with open(attachFile, "rb") as fh:
                    data = fh.read()
                attachment.set_payload(data)
                encoders.encode_base64(attachment)
                attachment.add_header(*header)
                message.attach(attachment)
            except IOError:
                errmsg = "Error opening attachment file %s" % file_to_attach
                print(errmsg)
                sys.exit(1)

بذلك نكون شرحنا أحد تطبيقات بايثون وهو كيفية استخدام البايثون في ارسال بريد إلكتروني مع كافة الخيارات المتاحة لذلك من ارسال البريد الإلكتروني لعدة جهات وارفاق ملف مع البريد. اذا عجبك المقال لا تنسى مشاركته عبر منصات التواصل الاجتماعي، كما وندعوكم لمتابعة حساباتنا في تويتر وفيسبوك وشبكة لينكد ان.

 

4 thoughts

    1. أهلا بكم وشكرًا على الملاحظة.
      الصراحة لم أرغب بتشتيت القارئ عن الهدف الرئيسي للمقالة وهو كيفية ارسال بريد الكتروني من خلال البايثون
      فاتني أن أنوه للقارئ أن يكون لديه معرفة مُسبقة بموضوع البرمجة الكائنية وان كُنت وضعت رابط لمقال حول ذلك
      نسعد بكم ويُشرفنا مروركم الكريم

اترك تعليقاً

لن يتم نشر عنوان بريدك الإلكتروني. الحقول الإلزامية مشار إليها بـ *