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

6 3٬920

تطبيقات بايثون عديدة ومتشعبة في أكثر من مجال، وذلك لما تتمتع به لغة البايثون من مزايا وخصائص تجعلها حلًا للعديد من المشاكل والعقبات. نُرحب بكم في هذا المقال الجديد من بايثونات والذي نتناول فيه أحد تطبيقات بايثون وهو كيفية التعامل مع مكتبة 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 أو مثيلاتها. لهذا المقال سننشئ حساب بريد إلكتروني من خلال جوجل بالعنوان pythonat.test@gmail.com، وسنحتاج أيضًا تفعيل خيار الوصول للتطبيقات الأقل أمانًا من الرابط التالي:

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 = 'pythonat.test@gmail.com'
rec_email = 'ibr860@gmail.com'
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 = 'pythonat.test@gmail.com'
rec_email = 'ibr860@gmail.com'
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 = pythonat.test@gmail.com

نُنشئ ملف بايثون جديد باسم 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='ibr860@gmail.com', 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)

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

 

6 Comments
  1. nour eldin says

    شكرا جزيلا لشرحكم الوافي ولكن كنت اتمني شرح الكود المكتوب بال oop بصورة أبسط

    1. ابراهيم البحيصي says

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

  2. Mahmoud S.Ali says

    شكرا جدا يهندسه وجزاك الله كل خير فهمت المكتبتين كويس الحمدلله وهدور اكتر عشان افهمهم شكرا شكرا

  3. IL0V3_PyTh0N says

    شرح راائع جدا وسلس وقرائة ممتعه شكرا لك ..
    بانتظار المزيد

  4. محمد says

    شكرا جزيلا وأسأل الله أن يجعله في ميزان حسناتكم

  5. HUSAM AL-SUMAIDAEE says

    السلام عليكم استاذ ابراهيم …..

    حقيقة مجهودكم الطيب اكثر من رائع …

    من ناحية الامان …. عملكم طيب واخذا بنظر الاعتبار ال security من خلال  ssl ولكن نستطيع اضافة احدى خوارزميات التشفير اليه ليصبح اكثر امانا …. اليس كذلك؟؟

اترك ردًا

Your email address will not be published.