الفريق العربي للبرمجةأرشيف المنتديات · 2000 – 2023
نسخة أرشيفية للقراءة فقط — التسجيل والمشاركة مغلقان، والمحتوى محفوظ كما كان.

مكتبة لإرسال البريد الجماعي مفتوحة المصدر

بدأه محمد رضى في 17 يناير 2011 · 23 رد · 2,853 مشاهدة · في JavaSE
مشاركة: واتساب X فيسبوك تيليجرام
#1 صاحب الموضوع

السلام عليكم و رحمة الله تعالى و بركاته...

إليكم أول مشروع برمجي لي بلغة الجافا و هو عبارة عن مكتبة فئات بسيطة تمكن أي مشروع تطبيق جافا من إرسال بريد جماعي لعدد غير محدود من المرسل إليهم.

هذه المكتبة تمكن تطبيقات الجافا من :

- إرسال رسائل نصية و/أو HTML

- الإرسال عبر خادم أو مجموعة خوادم SMTP مع إمكانية تشخيص كيفية التعامل مع الخادم

- تبسيط عملية إرفاق الملفات للرسائل

- CCs و BCCs

- التحكم في Charset و Content Transfer Encoding

- تشخيص نص الرسالة قبيل إرسالها مباشرة

- و أكثر...

هذا رابط المكتبة https://sourceforge.net/projects/javaemailer/

ستجدون على نفس الرابط المشروع المفتوح المصدر و مشروع تطبيق بسيط لفهم كيفية التعامل مع المكتبة و الفئات المكونة لها.

و هذا رابط نحو كود مشروع التعامل مع المكتبة لمن يريد قراءته سريعا دون تحميل https://sourceforge.net/projects/javaemailer/forums/forum/1354679/topic/4057153

المكتبة في نسختها Beta تعمل جيدا لكنها تحتاج لمزيد من الاختبارات و تحسين الكود المصدر للمزيد من الكفائة و السرعة وقت التنفيذ.

رجاءا لا تبخلوا علي بآرائكم و اقتراحاتكم :)

5
#2

رائع.. تمنياتي لك بالتوفيق

وأعتقد أنه في مكتبة جاهزة لهذا الشيء ، اللي هي JavaMail API

http://www.oracle.com/technetwork/java/index-jsp-139225.html

هل هناك فرق ؟ :unsure:

عفواً أحبتي انقطاعي بسبب الدراسة دعواتكم بالتوفيق..

{ لا ينال العلم مستحٍ ولا مستكبر }

#3

المكتبة JavaEmailer تستعمل المكتبة JavaMail في عملية الإرسال, دور JavaEmailer هو تسهيل عملية إرسال البريد الإلكتروني الجماعي من أي تطبيق جافا و هي معدة للعمل داخل مشاريع CRM و غيرها التي تكون معدة لتسيير قواعد بيانات بها عناوين إلكترونية لعملاء أو زبائن مثلا لتسهيل إرسال بريد جماعي مشخص لهم في أي وقت و بأقل مجهود.

شكرا أخي JavaProgrammer :)

1
#4

شكرا على التوضيح ، أرجو لك المزيد ..

:happy:

عفواً أحبتي انقطاعي بسبب الدراسة دعواتكم بالتوفيق..

{ لا ينال العلم مستحٍ ولا مستكبر }

#5

مشروع رائع اخ محمد

بالتوفيق والى الامام دائما


﴿وَمَا كَانَ اللَّهُ لِيُعَذِّبَهُمْ وَأَنْتَ فِيهِمْ ۚ وَمَا كَانَ اللَّهُ مُعَذِّبَهُمْ وَهُمْ يَسْتَغْفِرُونَ﴾

الأنفال ۳۳                                  
 

#6

بارك الله فيك أخي محمد

كما أود أن أوجه شكرا خاصا لأخي محمود الكيلاني للمجهود الذي قام به في قراءة و تحليل الكود الخاص بالمكتبة و آرائه و اقتراحاته القيمة لتطويرها.

#7
محمد رضى كتب:

بارك الله فيك أخي محمد

كما أود أن أوجه شكرا خاصا لأخي محمود الكيلاني للمجهود الذي قام به في قراءة و تحليل الكود الخاص بالمكتبة و آرائه و اقتراحاته القيمة لتطويرها.

لا شكر على واجب اخى محمد

اعانك الله وفققك وفقنا جميعا ان شاء الله :)

Software Developer
Mahmoudkelany.com


 

#8

بعد تنفيذ عملية ارسال بريد جماعي دائما ما تثبعها عملية استقبال بريد جماعي من الخوادم التي تم استعمالها في عملية الارسال. تقريبا 30% من عناوين البريد الإلكتروني في أي قائمة بريدية تصبح بالية بعد مرور سنة واحدة, لهذا فبعد كل عملية ارسال بريد جماعي تتبعها مهمة شاقة هي عملية تحرير القائمة البريدية لوضع علامة تميز العنوان الإلكتروني أو التسجيل الخاص بعميل مثلا أن العنوان الإلكتروني يحتاج إلى تحديث حتى لا نخسر الوقت بعد ذلك في ارسال رسائل لن تصل إلى أصحابها.

لم أقم بتضمين المكتبة JavaEmailer بقارئ للبريد الوارد لأنني كنت أظن أنه سيتوجب علي إنشاء أكواد لكل نوع من الخوادم (IMAP, POP3, etc.) المعدة لقراءة صناديق البريد الوارد Inboxes. لكن بما أن المكتبة الرائعة JavaMail قامت بتبسيط عملية قراءة البريد الوارد إلى أبعد حد فأظن أن فئة واحدة ستقوم بالعملية و لهذا فسأقوم بزيادة فئة إلى المكتبة تقوم بتمكين التطبيق المستعمل لـ JavaEmailer بقراءة البريد الوارد من حسابات البريد الالكتروني التي استعملت في عملية الارسال و ذلك للبحث عن أجوبة الخوادم في حال فشل إيصال رسائل إلى بعض المستلمين.

تصوري للفئة أنها ستقوم بربط الاتصال بخادم البريد و ستقوم باستعراض البريد الوارد رسالة رسالة بحثا عن محتوى ما (يحدده كود التطبيق) في عنوان الرسالة subject لتسريع عملية الاستعراض و عند تطابق شروط البحث على عنوان رسالة ما تقوم الفئة برفع حدث يمرر محتوى الرسالة تاركا للكود الخارجي حرية التصرف بعد ذلك. مثلا, عند فشل إيصال رسالة إلى عنوان ما يقوم الخادم بإرسال رسالة إلى المرسل عادة ما يكون عنوانها "Undeliverable: ..." أو "Returned mail: ..." ... في هذه الحالة يقوم كود التطبيق بوضع علامة تمنع مستقبلا تضييع الوقت في ارسال رسائل للعنوان المعلم عليه حتى يقوم أحدهم بتحديته و إزالة علامة المنع من عليه.

#9

ألن تصبح الخوادم المستعملة banned من طرف ال ISP أو طرف آخر على أساس أنها spammer؟؟

#10

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

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

إضافة : وكالات التسويق عبر البريد الإلكتروني تقوم بحجز اسم نطاق خاص بإرسال البريد الإلكتروني الجماعي لفائدة عملائها و عندما يتم تعليم اسم النطاق على أنه مرسل للبريد المزعج تقوم الوكالات بتغييره بواحد آخر نظيف و هكذا دواليك...

تم تعديل هذه المشاركة بواسطة محمد رضى في 23 يناير 2011 في 20:11 — السبب: إضافة

2
#11

عمل رائع , بارك الله فيك أخي :)


HeartOutputStream myHeart;
OutputStream myHeartOutStream;

myHeartOutStream = MAllaw.getHeart().getOutputStream();
myHeart = new HeartOutputStream(myHeartOutStream);

while(myHeart.isStillBeating())
myHeart.write("I ♥ Java");

#12

شكرا أخي M.Allaw بارك الله فيك :)

لتسهيل مهمة تحديث القائمة البريدية بعد القيام بعملية إرسال بريد جماعي قمت بزيادة الفئتين التاليتين :

InboxEmailsReader تقوم بربط الاتصال بخادم البريد الإلكتروني و البحث عن الرسائل حسب التعبير و الوسوم التي يتم تمريرها عبر الباني. الفئة تقوم بالعمل بطريقتين blocking and non blocking

EmailIterator هو Iterator ترجعه الدالة InboxEmailsReader.iterator() تمكن من استعراض الرسائل التي تتوفر فيها شروط البحث

NextInboxEmailEventArgs يتم تمرير كائن لهذه الفئة عند رفع الحدث EventManager.EventID.EID_NEXT_INBOX_EMAIL

EventManager.EventID.EID_NEXT_INBOX_EMAIL تمت زيادة هذا الحدث الذي يتم رفعه كلما تم إيجاد رسالة إلكتروني تتوفر فيها شروط البحث

هذا كود يبين بالتفصيل كيفية استعمال الفئات المذكورة :

// Sample program package
package javatestlab;


// For reading text files
import ejel.*;
import ejel.EventManager.EventID;
import java.io.IOException;
import javax.mail.*;
import java.util.*;


/**
 *
 * @author emmr.rida
 */
public class Main
{
    /**
     * @param args the command line arguments
     */
    public static void main(String[] args) throws NoSuchProviderException, MessagingException, IOException, InterruptedException
    {
        asyncSample(); // Uncomment to use non blocking services
        //syncSample(); // Uncomment to use blocking services
    }

    /**
     * Sample code of the InboxEmailsReader that uses blocking services to connect to an email account and search for email messages
     * @throws NoSuchProviderException
     * @throws MessagingException
     * @throws IOException
     */
    private static void syncSample() throws NoSuchProviderException, MessagingException, IOException
    {
        // Email account login information
        EmailAccount account = new EmailAccount("user@host.com", "password", "server_host_name", 0, true, EmailAccount.ServerProtocol.IMAP);
        // Constructs an object that will look for emails whose subject contains [Re :]
        InboxEmailsReader reader = new InboxEmailsReader(account, "Re :", false, new Flags());
        System.out.println("Connecting to server...");
        if(reader.connect()) { // Connect to server
            System.out.println("Connected to the server.");
            Iterator it = reader.iterator(); // Get the iterator
            while(it.hasNext()) { // While there are more Message objects
                Message msg = (Message)it.next(); // Retrieve the Message email object
                System.out.println(msg.getFrom()[0].toString() + " | " + msg.getSubject() + " | " + msg.getSentDate().toString());
            }
            reader.close(); // Cose the reader
        } else { // Error
            if(reader.getException() != null) reader.getException().printStackTrace();
        }
        System.out.println("Program terminated.");
    }

    /**
     * Sample code of the InboxEmailsReader that uses non blocking services to connect to an email account and search for email messages
     * @throws NoSuchProviderException
     * @throws MessagingException
     * @throws IOException
     * @throws InterruptedException
     */
    private static void asyncSample() throws NoSuchProviderException, MessagingException, IOException, InterruptedException
    {
        // The email account login information
        EmailAccount account = new EmailAccount("user@host", "password", "host_name", 0, true, EmailAccount.ServerProtocol.POP3);
        // Constructs an InboxEmailsReader and search for emails whose subjects matches the regular expressions
        InboxEmailsReader reader = new InboxEmailsReader(account, "Re[\\s]{0,1}:.*", true, new Flags());
        // Constructs a listener object
        MyEventListener listener = new MyEventListener();
        // Register the listener for the right event
        reader.registerEventListener(EventID.EID_NEXT_INBOX_EMAIL, listener);
        System.out.print("Connecting to server");
        reader.asyncConnect(); // Try to connect to server
        while(reader.isNowConnecting()) { // Wait for the connection
            System.out.print('.');
            Thread.sleep(250);
        }
        System.out.println('.');
        if(reader.isConnected()) { // Check success
            System.out.println("Connected to server.");
        }  else {
            reader.getException().printStackTrace();
            return;
        }
        // After the call a thread will be created and the search process begins.
        // For every email message that matches the search query, an event is
        // raised so as the registered listeners will check the email message.
        reader.asyncIterator();
        while(reader.isIterating()) Thread.sleep(250); // Wait for the search process to finish
        reader.close(); // Close the reader
        System.out.println("Program terminated.");
    }
}

/**
 * Here's our simple listener for the InboxEmailsReader events
 * must implement the EventListener
 * @author emmr.rida
 */
class MyEventListener implements ejel.EventListener
{
    /**
     * The asynchronous search process will raise the EventID.EID_NEXT_INBOX_EMAIL
     * event for each emai message found and call that function to process the email message
     * @param sender The InboxEmailsReader object who raised the event
     * @param evtId The event ID
     * @param evtParams Params for the event
     */
    public void eventListener(Object sender, EventID evtId, EventArgs evtParams) {
        if(evtId == EventID.EID_NEXT_INBOX_EMAIL) {
            NextInboxEmailEventArgs ea = (NextInboxEmailEventArgs)evtParams;
            try {
                System.out.println(ea.getMessage().getFrom()[0].toString() + " | " + ea.getMessage().getSubject() + " | " + ea.getMessage().getSentDate().toString());
                //ea.setAbortStatus(); // To abort the asynchronous search process
            } catch(Exception ex) {
                System.out.println(ex.getMessage());
            }
        } else assert false : "That must never happens!";
    }
}

مرفق مع هذا الرد الإصدارة Beta و أتمنى ممن لديه الوقت و الذهن الرايق :D أن يمدني بملاحظاته و آرائه و لكم جزيل الشكر

JavaEmailer.zip

#13

استخدم Thread pool بدلاً من فتح thread لكل مستقبل

لا تستخدم هذا الشكل التالي من الشيفرة أبداً

		while (!engine.isFinished())
			; /* * Sender engine has finished the mass mailin operation */

واستعوض عنه بـ wait/notify

الصراحة أني لا أحب قراءة الشيفرة الخاصة بالآخرين

لذا أعطني فكرة عن الشيفرة بالعربي

تحياتي

حزمة المحرك الإصدارة 0.8

أي أحد يجد أني ظلمته فليراسلني

وبإذن الله لو كان له حق سيأخذه

728x90.png

#14

الكود المرفق هو برنامج بسيط للتجربة فقط يبين طرق استعمال الفئات الجديدة في المكتبة التي استخدم فيها Thread pool كما أشرت إليه في ردك أخي علاء.

لو أمكن أن تلقي نظرة على كود المكتبة في الملف المرفق هو الذي يهمني أكثر :)

#15

ممتاز وفقك الله وان شاء الله للافضل

إذا نظــرتَ نيـوب اللـّيـثِ بـارزةً         فـلا تظــنَنَ أَنَّ اللـّيـــثَ يبْتسـِـــمُ


 


 


رسم المخططات البيانية بواسطة الجافا


 


كتاب تحليل وتصميم نظم المعلومات


#16

لن أستطيع قراءة الشيفرة كاملة

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

ساحاول المساعدة

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

تحياتي

حزمة المحرك الإصدارة 0.8

أي أحد يجد أني ظلمته فليراسلني

وبإذن الله لو كان له حق سيأخذه

728x90.png

#17

بارك الله فيك أخي vector_ever :)

شكرا أخي علاء و بارك الله فيك :) ما أحتاجه حاليا هو تجربة المكتبة من طرف أشخاص آخرين غيري و قراءة الكود للنظر فيما إذا كان بالإمكان القيام ببعض العمليات بشكل أفضل مما هو عليه الآن و كذلك آراء و اقتراحات حول ما إذا كان المنطق العام لفئات المكتبة خصوصا تعدد المسالك و نظام الأحداث و نظام التخاطب مع الكود الخارجي يتفق مع روح لغة الجافا أم لا.

#18
if(reader.getException() != null) reader.getException().printStackTrace();

ممكن اخ محمد توضح استخدام هذا الاسلوب؟

مقتبس من مشاركتك في الاعلى

ان توفر الوقت لي في هذه الفترة ان شاء الله، سوف اقرأ الكود كله

#19
.S.T.A.L.K.E.R كتب:

if(reader.getException() != null) reader.getException().printStackTrace();

ممكن اخ محمد توضح استخدام هذا الاسلوب؟

مقتبس من مشاركتك في الاعلى

ان توفر الوقت لي في هذه الفترة ان شاء الله، سوف اقرأ الكود كله

رغبة مني في إعادة استعمال الدالة InboxEmailsReader.connect() تفاديا لكتابة نفس الكود في الدالة InboxEmailReader.asyncConnect() قمت بكتابة الكود بشكل يقوم وقت حدوث أي استثناء بإحالة القيمة false إلى المتغير InboxEmailsReader.isConnected و الكائن الممثل للاستثناء الذي تم رفعه في المتغير InboxEmailsReader.exception بهذه الطريقة يمكن أن أنفذ نفس كود ربط الاتصال بالخادم بالطريقتين blocking and non blocking مع ظمان أنه في حالة رفع استثناء في مسلك آخر يستطيع الكود الخارجي التعرف عليه بدون مشاكل خصوصا أن المناداة على الدالة InboxEmailsReader.asyncConnect() يقوم بتنفيذ كود ربط الاتصال على مسلك خاص لهذا الغرض و يمكن للتطبيق عمل ما يشاء في انتظار ربط الاتصال بالخادم دون التسبب بتجميده الشيء الذي سيحدث في حالة المناداة على الدالة InboxEmailsReader.connect().

        // The email account login information
        EmailAccount account = new EmailAccount("user@host", "password", "host_name", 0, true, EmailAccount.ServerProtocol.POP3);
        // Constructs an InboxEmailsReader and search for emails whose subjects matches the regular expressions
        InboxEmailsReader reader = new InboxEmailsReader(account, "Re[\\s]{0,1}:.*", true, new Flags());
        // Constructs a listener object
        MyEventListener listener = new MyEventListener();
        // Register the listener for the right event
        reader.registerEventListener(EventID.EID_NEXT_INBOX_EMAIL, listener);
        System.out.print("Connecting to server");
        reader.asyncConnect(); // Try to connect to server
        while(reader.isNowConnecting()) { // Wait for the connection
            System.out.print('.');
            Thread.sleep(250);
        }
        System.out.println('.');
        if(reader.isConnected()) { // Check success
            System.out.println("Connected to server.");
        }  else {
            reader.getException().printStackTrace();
            return;
        }
        // After the call a thread will be created and the search process begins.
        // For every email message that matches the search query, an event is
        // raised so as the registered listeners will check the email message.
        reader.asyncIterator();
        while(reader.isIterating()) Thread.sleep(250); // Wait for the search process to finish
        reader.close(); // Close the reader
        System.out.println("Program terminated.");

شكرا أخي .S.T.A.L.K.E.R :)

#20
علاء الصالحي كتب:

لا تستخدم هذا الشكل التالي من الشيفرة أبداً

		while (!engine.isFinished())
			; /* * Sender engine has finished the mass mailin operation */

واستعوض عنه بـ wait/notify

طريقة الانتظار هاته سيتم العمل بها في تطبيقات سطح المكتب حيث سيقوم التطبيق بعرض animation أو progress bar (marquee) تنبه المستخدم أن التطبيق يعمل حاليا و ليس جامدا في انتظار أن الكائن من فئة SenderEngine يتم عمله الذي ينفذ في مسلك خاص تفاديا لتجميد التطبيق المستخدم لخدمات المكتبة JavaEmailer.

استخدام wait/notify سيقوم بتجميد المسلك الرئيس للتطبيق في انتظار انتهاء SenderEngine من عمله الذي قد يدوم لساعات حسب عدد المرسل إليهم و سرعة الارسال.

تم تعديل هذه المشاركة بواسطة محمد رضى في 26 يناير 2011 في 16:51

#21

هذا الأسلوب يعتبر مستهلك للمعالج بشكل يفوق الوصف

بالنسبة لآلية العرض التي تتكلم عليها

هناك آليتين مشهورتين للحصول على تحديثات البرامج

1- الصموت push

في هذه الآلية يقوم التطبيق المعني بأمر الحزمة بانتظار صدور حدث عن الحزمة event نظام الأحداث في الجافا يعتمد على هذا المبدأ

2- الثرثار pull

في هذه الآلية يقوم التطبيق المعني بأمر الحزمة بسؤال الحزمة عن أشياء معينة هل انتهيت من الإرسال؟ هل انتهيت من الإرسال؟ كل فترة والثانية

الصراحة أن الأولى هي الأوسع انتشاراً والأقل كلفة

لكن الثانية موجودة ومستخدمة أيضاً وهي ما استخدمته هنا لكنا هنا عدائية بشكل واضح بحيث تطلب بشكل متكرر بدون ترك مسافات واضحة ما بين كل طلب وآخر

الصراحة أنه بدا لي أنك تستخدمها حتى لا ينتهي البرنامج الخاص بك

لذا اقترحت wait notify

لكن إذا كانت فكرتك من الموضوع أن تحصل على التحديثات لبرنامجك فابحث عن نمط المراقب observer (هذا النمط يستخدم لبناء الصموت push)

تحياتي

1
حزمة المحرك الإصدارة 0.8

أي أحد يجد أني ظلمته فليراسلني

وبإذن الله لو كان له حق سيأخذه

728x90.png

#22

جميل جدا, بارك الله فيك. سوف أقوم بعدة قراءات في الموضوع لأرتب كيفية تحديث المكتبة للعمل بالأسلوب المناسب في اصدارة لاحقة إن شاء الله...

تم تعديل هذه المشاركة بواسطة محمد رضى في 26 يناير 2011 في 22:35

#23

بالنسبة لآليات الحصول على تحديثات التطبيقات المستخدمة لمكتبة JavaEmailer فهناك آليتين, ربما لا تتبعان المنهج القياسي التي وضعته جافا لتطبيقاتها لكن أظن, و حتى تبوت العكس, أنهما تفيان بالغرض.

الآلية الأولى معدة للعمل مع تطبيقات سطر الأوامر Console applications التي نحتاج خلالها لمنع الخروج من التطبيق حتى تنتهي SenderEgine أو InboxEmailsReader من عملها. مثال :

...
senderEngine.startEngine();
while(!senderEngine.isFinished()) {
    Thread.sleep(1000);
}

أما بالنسبة لتطبيقات سطح المكتب التي تبقى نشطة حتى يقوم المستخدم بطلب إيقافها فالفئتين الرئيسيتين في المكتبة SenderEngine و InboxEmailsReader لها أحداث تمكن التطبيق المستخدم لهما من التعرف على حالتها وقت أي تغيير عن طريق تسجيل مستمع لهذه الأحداث دون الحاجة لطلب حالة التحديثات مرة بعد مرة عن طريق لوب. بالنسبة للفئة SenderEngine الحدث EventID.EID_STARTED يخبر التطبيق ببدء عملية الإرسال و EventID.EID_FINISHED يخبر بانتهائها و بينهما أحداث أخرى بالطبع. أما الفئة InboxEmailsReader و تفاديا لتعقيد الأمور تم اختصار عمل الفئة في حدث واحد هو EventID.EID_NEXT_INBOX_EMAIL حيث بداية عمل الفئة تكون عبر المناداة على الدالة asyncConnect() و نهاية العمل تكون عندما يتم تحديد المتغير NextInboxEmailEventArgs.hasNext على false حيث NextInboxEmailEventArgs هو الكائن الذي يتم تمريره كـ params إلى التطبيق المستمع لأحداث الفئة InboxEmailsReader.

سأقوم بتحديث الفئتين لتمكين تطبيقات سطر الأوامر من استخدام الدالة wait لانتظار الانتهاء من العمل و سأبقي على الطريقة الأولى في حالة ما إذا كان التطبيق يحتاج إلى تنفيذ كود ما في انتظار الانتهاء من العمل.

#24

هذه لائحة بعدة أفكار للإصدارة التالية من المكتبة :

- زيادة إمكانية عمل cache لعناوين أيبي خوادم SMTP لتسريع عملية الارسال و ذلك عن طريق ربط الاتصال مباشرة مع الخادم دون المرور عبر خادم DNS في كل مرة.

- زيادة امكانية استخدام Proxy في عملية الارسال.

- زيادة دوال إلى الفئة InboxEmailsReader تسهل على المبرمج عملية القراءة و البحث في الرسائل الموجودة داخل صندوق البريد الوارد.

مواضيع مشابهة