Solved

utl_mail - Sending query as an attachment

Posted on 2013-12-05
11
674 Views
Last Modified: 2013-12-19
Hi,

I have a requirement to send query results in an email from an oracle database. I have begun the procedure but really need help with the following:
1.I need to modify the query to search for ENTRY DATEs created in the past two days.
2.I will have a table with email addresses and only want to send specific reps the query don't know how to put this in the cursor

Any help will be greatly appreciated. I'm new to Oracle

CREATE OR REPLACE PROCEDURE SALESMAIL AS 
 
DECLARE
  lv_sender VARCHAR2(200) :='First.Last@Company.com';
  lv_recipients VARCHAR2(200) :='First.Last@Company.com';
  lv_subject VARCHAR(200) :='Test Small Quotes';
  lv_priority PLS_INTEGER := NULL;
  lv_last     BOOLEAN := FALSE;
  lv_count NUMBER := 0;
  lv_message VARCHAR2(32000);
  lv_conn  utl_smtp.connection;
 
  CURSOR cur_query
  IS
15.  SELECT ("CQ_HEADER"."BILL_NAME", "CQ_HEADER"."CQ_NUMBER", "CQ_HEADER"."TOTAL_PRICE", "CQ_STATUS"."STATUS_CODE", "SALESPERSON"."SALESPERSON_NAME", "CQ_HEADER"."ENTRY_DATE", "CQ_HEADER"."EMAIL_ADDRESS", "CQ_HEADER"."PHONE_NUMBER", "CQ_HEADER"."ATTENTION", "CQ_HEADER"."NOTES")a
  FROM   ("QCTL"."CQ_HEADER" "CQ_HEADER" LEFT OUTER JOIN "QCTL"."CQ_STATUS" "CQ_STATUS" ON "CQ_HEADER"."CQS_AUTO_KEY"="CQ_STATUS"."CQS_AUTO_KEY") LEFT OUTER JOIN "QCTL"."SALESPERSON" "SALESPERSON" ON "CQ_HEADER"."SPN_AUTO_KEY"="SALESPERSON"."SPN_AUTO_KEY"
  WHERE  "CQ_HEADER"."TOTAL_PRICE">=2000 AND "CQ_STATUS"."STATUS_CODE"='TRACKING' AND ("CQ_HEADER"."ENTRY_DATE">TO_DATE ('21-09-2013 00:00:00', 'DD-MM-YYYY HH24:MI:SS') AND "CQ_HEADER"."ENTRY_DATE"<=TO_DATE ('04-11-2013 00:00:00', 'DD-MM-YYYY HH24:MI:SS'))
  ORDER BY "CQ_HEADER"."BILL_NAME", "CQ_HEADER"."ENTRY_DATE", "CQ_HEADER"."TOTAL_PRICE" DESC
  connect by level <=1000;

  BEGIN
    lv_conn:= SALESMAIL.begin_mail
                  ( lv_sender
                    , lv_recipients
                    , lv_subject
                    , SALESMAIL.multipart_mime_type
                    , lv_priority
                  );
 
    SALESMAIL.begin_attachment
          ( lv_conn
            ,'text/html"
            , FALSE
            ,'test.csv"
           ,'7 bit'
            );
 
    FOR rec IN cur_query
    LOOP
     lv_message := lv_message||rec.a||chr(13);
      SALESMAIL.write_text(lv_conn, lv_message);
    END LOOP;
 
    SALESMAIL.end_attachment
       ( lv_conn
           ,TRUE
         );
 
         SALESMAIL.end_mail(lv_conn);
        END;
 
BEGIN
  NULL;
END SALESMAIL;

Open in new window

0
Comment
Question by:Annette Wilson, MSIS
  • 6
  • 5
11 Comments
 
LVL 73

Accepted Solution

by:
sdstuber earned 500 total points
ID: 39699855
I don't know what the salesmail package is in the code above.

utl_mail has its own api, you don't do begin/end attachment.    You simply pass in a varchar2 variable with your attachment text

if you need more than a varchar2 will hold (32K) then use utl_smtp.

example of how to use utl_smtp including sending the results of a query can be found in this article...

http://www.experts-exchange.com/Database/Oracle/A_7749-How-to-send-email-attachments-with-Oracle.html
0
 

Author Comment

by:Annette Wilson, MSIS
ID: 39702190
Thank your for responding sdstuber,

Just not sure how to correctly hardcode test email recipients but,

I revised the following and an getting two errors:

Error(3,1): PLS-00103: Encountered the symbol "DECLARE" when expecting one of the following:     begin function pragma procedure subtype type <an identifier>    <a double-quoted delimited-identifier> current cursor delete    exists prior external language The symbol "begin" was substituted for "DECLARE" to continue.

Error(11,47): PLS-00103: Encountered the symbol "OUTER" when expecting one of the following:     ) , for group having intersect minus order start union where    connect

CREATE OR REPLACE PROCEDURE SMQUOTESMAIL AS

DECLARE v_connection UTL_SMTP.connection;
        v_clob   CLOB := EMPTY_CLOB();
        v_len    INTEGER;
        v_index  INTERGER;


BEGIN
FOR x IN (SELECT "CQ_HEADER"."BILL_NAME", "CQ_HEADER"."CQ_NUMBER", "CQ_HEADER"."TOTAL_PRICE", "CQ_STATUS"."STATUS_CODE", "SALESPERSON"."SALESPERSON_NAME", "CQ_HEADER"."ENTRY_DATE", "CQ_HEADER"."EMAIL_ADDRESS", "CQ_HEADER"."PHONE_NUMBER", "CQ_HEADER"."ATTENTION", "CQ_HEADER"."NOTES"
  FROM   "QCTL"."CQ_HEADER", "CQ_HEADER" LEFT OUTER JOIN "QCTL"."CQ_STATUS", "CQ_STATUS" ON "CQ_HEADER"."CQS_AUTO_KEY"="CQ_STATUS"."CQS_AUTO_KEY") LEFT OUTER JOIN "QCTL"."SALESPERSON", "SALESPERSON" ON "CQ_HEADER"."SPN_AUTO_KEY"="SALESPERSON"."SPN_AUTO_KEY")
  WHERE  "CQ_HEADER"."TOTAL_PRICE"<=2000 AND "CQ_STATUS"."STATUS_CODE"='TRACKING' AND ("CQ_HEADER"."ENTRY_DATE">TO_DATE ('21-11-2013 00:00:00', 'DD-MM-YYYY HH24:MI:SS') AND "CQ_HEADER"."ENTRY_DATE"<=TO_DATE ('04-12-2013 00:00:00', 'DD-MM-YYYY HH24:MI:SS')
  ORDER BY "CQ_HEADER"."BILL_NAME", "CQ_HEADER"."ENTRY_DATE", "CQ_HEADER"."TOTAL_PRICE" DESC
  
  LOOP
    v_clob :=
    v_clob
    || x
    || ','
    || TO_CHAR(x.created, 'yyyy-mm-dd hh24:mi:ss')
    || UTL_TCP.crlf;
    END LOOP;
    
    v_connection := UTL_SMTP.open_connection(:p_smtp_server);
    UTL_SMTP.helo(v_connection, :p_domain);
    UTL_SMTP.mail(v_connection, :p_from);
    UTL_SMTP.rcpt(v_connection, :p_to);
    UTL_SMTP.open_data(v_connection);
    
    UTL_SMTP.write_data(v_connection, 'From: ' || :p_from || UTL_TCP.crlf);
    UTL_SMTP.write_data(v_connection, 'To: ' || :'First.Last@ontic.com' || UTL_TCP.crlf);
    UTL_SMTP.write_data(v_connection, 'Subject: test subject'  ||  UtL_TCP.crlf);
    UTL_SMTP.write_data(v_connection, UTL_TCP.crlf);
    v_len := DBMS_LOB.getlength(v_clob);
    v_index :=1;
    
    WHILE v_index <= v_len
    LOOP
       UTL_SMTP.write_data(v_connection, DBMS_LOB.SUBSTR(v_clob, 32000, v_index));
       v_index := v_index + 32000;
       END LOOP;
       
       UTL_SMTP.wirte_data(v_connection, UTL_TCP.crlf);
       
       UTL_SMTP.close_data(v_connection);
       UTL_SMTP.quit(v_connection);
       EXCEPTION
         WHEN OTHERS
         THEN
            DBMS_OUTPUT.put_line(DBMS_UTILITY.format_error_stack);
END SMQUOTESMAIL;

Open in new window

0
 
LVL 73

Assisted Solution

by:sdstuber
sdstuber earned 500 total points
ID: 39709790
there are multiple syntax errors

you have DECLARE in there which doesn't apply inside of a procedure.
In your cursor for loop you have random commas and periods and some table names are duplicated.

you are referencing x.created but that's not one of the columns returned by your query


you need to supply strings for the variables that have colons in front of them

:p_smtp_server  should either be a server name or ip address
:p_domain  should be something like 'google.com'  in your case, probably 'ontic.com'
:p_from  in the utl_smtp.mail line should be the address you want any email error messages returned to

:p_to in the utl_smtp.rcpt is the address of who you are sending to.  Just the address, no names or titles

the other :p_from and :p_to  in the write_data are actually optional.  They are the values that the recipient will see in their email client; but aren't actually required.  It is common for them to be the same, possibly with names included.

don't put the colons in front of your strings though, that's just for using bind variables which you don't want to do if you're putting that code into a procedure

so  this is wrong...
 :'First.Last@ontic.com'

just do this...

 'First.Last@ontic.com'
0
 

Author Comment

by:Annette Wilson, MSIS
ID: 39722915
Thank you for following up!  I really appreciate this.  I am not familiar with Oracle syntax for sending email.

I'm getting the following errors now.

Error(10,3): PL/SQL: SQL Statement ignored
Error(15,3): PL/SQL: ORA-00933: SQL command not properly ended
Error(21,9): PLS-00113: END identifier 'LOOP' must match 'SMQUOTESMAIL' at line 1, column 11
Error(23,5): PLS-00103: Encountered the symbol "V_CONNECTION"
Error(23,46): PLS-00103: Encountered the symbol ":" when expecting one of the following:     ( ) - + case mod new not null <an identifier>    <a double-quoted delimited-identifier> <a bind variable>    table continue avg count current exists max min prior sql    stddev sum variance execute multiset the both leading    trailing forall merge year month day hour minute second    timezone_hour timezone_minute timezone_region timezone_abbr    time timestamp interval date    <a string literal with character set specification>

CREATE OR REPLACE PROCEDURE SMQUOTESMAIL AS

 v_connection UTL_SMTP.connection;
        v_clob   CLOB := EMPTY_CLOB();
        v_len    INTEGER;
        v_index  INTERGER;


BEGIN
  SELECT "CQ_HEADER"."BILL_NAME", "CQ_HEADER"."CQ_NUMBER", "CQ_HEADER"."TOTAL_PRICE", "CQ_STATUS"."STATUS_CODE", "SALESPERSON"."SALESPERSON_NAME", "CQ_HEADER"."ENTRY_DATE", "CQ_HEADER"."EMAIL_ADDRESS", "CQ_HEADER"."PHONE_NUMBER", "CQ_HEADER"."ATTENTION", "CQ_HEADER"."NOTES"
  FROM   "QCTL"."CQ_HEADER" LEFT OUTER JOIN "QCTL"."CQ_STATUS" ON "CQ_HEADER"."CQS_AUTO_KEY"="CQ_STATUS"."CQS_AUTO_KEY" LEFT OUTER JOIN "QCTL"."SALESPERSON" ON "CQ_HEADER"."SPN_AUTO_KEY"="SALESPERSON"."SPN_AUTO_KEY"
  WHERE  "CQ_HEADER"."TOTAL_PRICE"<=2000 AND "CQ_STATUS"."STATUS_CODE"='TRACKING' AND "CQ_HEADER"."ENTRY_DATE">TO_DATE ('21-11-2013 00:00:00', 'DD-MM-YYYY HH24:MI:SS') AND "CQ_HEADER"."ENTRY_DATE"<=TO_DATE ('04-12-2013 00:00:00', 'DD-MM-YYYY HH24:MI:SS')
  ORDER BY "CQ_HEADER"."BILL_NAME", "CQ_HEADER"."ENTRY_DATE", "CQ_HEADER"."TOTAL_PRICE" DESC
  
  LOOP
    v_clob :=
    v_clob
    || ','
    || TO_CHAR(x.created, 'yyyy-mm-dd hh24:mi:ss')
    || UTL_TCP.crlf;
    END LOOP;
    
    v_connection := UTL_SMTP.open_connection(:'MYconnection');
    UTL_SMTP.helo(v_connection, :'mydomain');
    UTL_SMTP.mail(v_connection, :'my.name@company.com');
    UTL_SMTP.rcpt(v_connection, :'manager.name@company.com');
    UTL_SMTP.open_data(v_connection);
    
    UTL_SMTP.write_data(v_connection, 'From: ' || 'my.name@company.com'|| UTL_TCP.crlf);
    UTL_SMTP.write_data(v_connection, 'To: ' || 'my.name@company.com'|| UTL_TCP.crlf);
    UTL_SMTP.write_data(v_connection, 'Subject: COMPANY TEST'  ||  UtL_TCP.crlf);
    UTL_SMTP.write_data(v_connection, UTL_TCP.crlf);
    v_len := DBMS_LOB.getlength(v_clob);
    v_index :=1;
    
    WHILE v_index <= v_len
    LOOP
       UTL_SMTP.write_data(v_connection, DBMS_LOB.SUBSTR(v_clob, 32000, v_index));
       v_index := v_index + 32000;
       END LOOP;
       
       UTL_SMTP.wirte_data(v_connection, UTL_TCP.crlf);
       
       UTL_SMTP.close_data(v_connection);
       UTL_SMTP.quit(v_connection);
       EXCEPTION
         WHEN OTHERS
         THEN
            DBMS_OUTPUT.put_line(DBMS_UTILITY.format_error_stack);
END SMQUOTESMAIL;

Open in new window

0
 
LVL 73

Assisted Solution

by:sdstuber
sdstuber earned 500 total points
ID: 39722922
you took the for loop out, put that back in.

    FOR x
        IN (SELECT "CQ_HEADER"."BILL_NAME",
                   "CQ_HEADER"."CQ_NUMBER",
                   "CQ_HEADER"."TOTAL_PRICE",
                   "CQ_STATUS"."STATUS_CODE",
                   "SALESPERSON"."SALESPERSON_NAME",
                   "CQ_HEADER"."ENTRY_DATE",
                   "CQ_HEADER"."EMAIL_ADDRESS",
                   "CQ_HEADER"."PHONE_NUMBER",
                   "CQ_HEADER"."ATTENTION",
                   "CQ_HEADER"."NOTES"
              FROM "QCTL"."CQ_HEADER"
                   LEFT OUTER JOIN "QCTL"."CQ_STATUS"
                       ON "CQ_HEADER"."CQS_AUTO_KEY" = "CQ_STATUS"."CQS_AUTO_KEY"
                   LEFT OUTER JOIN "QCTL"."SALESPERSON"
                       ON "CQ_HEADER"."SPN_AUTO_KEY" = "SALESPERSON"."SPN_AUTO_KEY"
             WHERE "CQ_HEADER"."TOTAL_PRICE" <= 2000
               AND "CQ_STATUS"."STATUS_CODE" = 'TRACKING'
               AND "CQ_HEADER"."ENTRY_DATE" >
                       TO_DATE('21-11-2013 00:00:00', 'DD-MM-YYYY HH24:MI:SS')
               AND "CQ_HEADER"."ENTRY_DATE" <=
                       TO_DATE('04-12-2013 00:00:00', 'DD-MM-YYYY HH24:MI:SS')
            ORDER BY "CQ_HEADER"."BILL_NAME",
                     "CQ_HEADER"."ENTRY_DATE",
                     "CQ_HEADER"."TOTAL_PRICE" DESC)

Open in new window



also, like I said above you do NOT want the colons in front of those variables.  you only want the values

so, don't do this...

:'my.name@company.com'

do this...

'my.name@company.com'
0
PRTG Network Monitor: Intuitive Network Monitoring

Network Monitoring is essential to ensure that computer systems and network devices are running. Use PRTG to monitor LANs, servers, websites, applications and devices, bandwidth, virtual environments, remote systems, IoT, and many more. PRTG is easy to set up & use.

 

Author Comment

by:Annette Wilson, MSIS
ID: 39724512
Thank you.  I really appreciate your help.

I get the following errors.  

1. How do I correctly declare in Oracle
2. I will also have to declare a variable for email addresses.  The email will be sent to various individuals based on data in a table.  I will select the email address with the quote data and send it to each individual.

Procedure QCTL.SMQUOTESMAIL@maxqprod
Error(6,18): PLS-00201: identifier 'INTERGER' must be declared
Error(6,18): PL/SQL: Item ignored
Error(37,5): PL/SQL: Statement ignored
Error(40,18): PLS-00302: component 'CREATED' must be declared
Error(55,5): PLS-00320: the declaration of the type of this expression is incomplete or malformed
Error(55,5): PL/SQL: Statement ignored
Error(57,5): PL/SQL: Statement ignored
Error(57,11): PLS-00320: the declaration of the type of this expression is incomplete or malformed
Error(63,8): PL/SQL: Statement ignored
Error(63,17): PLS-00302: component 'WIRTE_DATA' must be declared

CREATE OR REPLACE PROCEDURE SMQUOTESMAIL AS

 v_connection UTL_SMTP.connection;
        v_clob   CLOB := EMPTY_CLOB();
        v_len    INTEGER;
        v_index  INTERGER;


BEGIN
  FOR x
        IN (SELECT "CQ_HEADER"."BILL_NAME",
                   "CQ_HEADER"."CQ_NUMBER",
                   "CQ_HEADER"."TOTAL_PRICE",
                   "CQ_STATUS"."STATUS_CODE",
                   "SALESPERSON"."SALESPERSON_NAME",
                   "CQ_HEADER"."ENTRY_DATE",
                   "CQ_HEADER"."EMAIL_ADDRESS",
                   "CQ_HEADER"."PHONE_NUMBER",
                   "CQ_HEADER"."ATTENTION",
                   "CQ_HEADER"."NOTES"
              FROM "QCTL"."CQ_HEADER"
                   LEFT OUTER JOIN "QCTL"."CQ_STATUS"
                       ON "CQ_HEADER"."CQS_AUTO_KEY" = "CQ_STATUS"."CQS_AUTO_KEY"
                   LEFT OUTER JOIN "QCTL"."SALESPERSON"
                       ON "CQ_HEADER"."SPN_AUTO_KEY" = "SALESPERSON"."SPN_AUTO_KEY"
             WHERE "CQ_HEADER"."TOTAL_PRICE" <= 2000
               AND "CQ_STATUS"."STATUS_CODE" = 'TRACKING'
               AND "CQ_HEADER"."ENTRY_DATE" >
                       TO_DATE('21-11-2013 00:00:00', 'DD-MM-YYYY HH24:MI:SS')
               AND "CQ_HEADER"."ENTRY_DATE" <=
                       TO_DATE('04-12-2013 00:00:00', 'DD-MM-YYYY HH24:MI:SS')
            ORDER BY "CQ_HEADER"."BILL_NAME",
                     "CQ_HEADER"."ENTRY_DATE",
                     "CQ_HEADER"."TOTAL_PRICE" DESC) 
  
  LOOP
    v_clob :=
    v_clob
    || ','
    || TO_CHAR(x.created, 'yyyy-mm-dd hh24:mi:ss')
    || UTL_TCP.crlf;
    END LOOP;
    
    v_connection := UTL_SMTP.open_connection('mysmpt_connection');
    UTL_SMTP.helo(v_connection, 'mydomain');
    UTL_SMTP.mail(v_connection, 'myname@company.com');
    UTL_SMTP.rcpt(v_connection, 'manager.name@company.com');
    UTL_SMTP.open_data(v_connection);
    
    UTL_SMTP.write_data(v_connection, 'From: ' || 'myname@company.com' || UTL_TCP.crlf);
    UTL_SMTP.write_data(v_connection, 'To: ' || 'my.name@company.com' || UTL_TCP.crlf);
    UTL_SMTP.write_data(v_connection, 'Subject: TEST'  ||  UtL_TCP.crlf);
    UTL_SMTP.write_data(v_connection, UTL_TCP.crlf);
    v_len := DBMS_LOB.getlength(v_clob);
    v_index :=1;
    
    WHILE v_index <= v_len
    LOOP
       UTL_SMTP.write_data(v_connection, DBMS_LOB.SUBSTR(v_clob, 32000, v_index));
       v_index := v_index + 32000;
       END LOOP;
       
       UTL_SMTP.wirte_data(v_connection, UTL_TCP.crlf);
       
       UTL_SMTP.close_data(v_connection);
       UTL_SMTP.quit(v_connection);
       EXCEPTION
         WHEN OTHERS
         THEN
            DBMS_OUTPUT.put_line(DBMS_UTILITY.format_error_stack);
END SMQUOTESMAIL;

Open in new window

0
 
LVL 73

Expert Comment

by:sdstuber
ID: 39724928
The errors are fairly self explanatory.

Error(6,18): PLS-00201: identifier 'INTERGER' must be declared

Open in new window


there is no such data type as "INTERGER"

Looks like you misspelled "INTEGER"


Error(40,18): PLS-00302: component 'CREATED' must be declared

Open in new window


you are trying use x.created in your code but your for loop "x" doesn't return any columns named "CREATED" from the sql.  

Looks likethat's a line you copied from my article but didn't change it to reflect what you are doing.  In that article, I queried "created" in my sql.  You must use the columns in your sql.


Error(63,17): PLS-00302: component 'WIRTE_DATA' must be declared

Open in new window


You are trying to call a procedure called "WIRTE_DATA" but no such procedure exists.

Looks like you misspelled "write_data"
0
 

Author Comment

by:Annette Wilson, MSIS
ID: 39725137
Thank you.  I know that I need to read up on writing oracle procedures and to watch my spelling.  

I still get the following regarding the loop:

Error(37,5): PL/SQL: Statement ignored
Error(40,8): PLS-00306: wrong number or types of arguments in call to 'TO_CHAR'

Just don't understand how this loop works and how I need to include the data in it.

LOOP
    v_clob :=
    v_clob
    || ','
    || TO_CHAR(x, 'yyyy-mm-dd hh24:mi:ss')
    || UTL_TCP.crlf;
    END LOOP;


When I remove the TO_CHAR statement, it compiles well.

In SQL I normally create a stored procedure and I can set up a job to execute it and I can send email.  do you have a good book reference on Oracle functionality?  

I'm getting the following error:

Connecting to the database databasename.
ORA-24247: network access denied by access control list (ACL)
Process exited.
Disconnecting from the database databasename.
0
 
LVL 73

Assisted Solution

by:sdstuber
sdstuber earned 500 total points
ID: 39725201
TO_CHAR(x, 'yyyy-mm-dd hh24:mi:ss')


x is just the handle for the FOR loop.  You must include some value from your loop query you want to include in the attachment

for example:

v_clob :=
    v_clob
    || ','
    || x.bill_name
    || UTL_TCP.crlf;

you don't need to use to_char unless you are converting a non-character value like a number, date or timestamp


for ACL's  see one of my other articles.
You'll need help from your DBA

http://www.experts-exchange.com/Database/Oracle/A_8429-How-to-use-Access-Control-Lists-in-Oracle.html
0
 

Author Comment

by:Annette Wilson, MSIS
ID: 39729804
Thank you for your help.  Our DBA will install the appropriate libraries tonight.

I just need help on one more item.

In the data set, I will include an email address for each sales person.  
I want an email to go to each sales person with his own data set in the email.

How do I create a variable that will enable me to loop through and send the appropriate email to the salesperson?
0
 
LVL 73

Expert Comment

by:sdstuber
ID: 39729841
I think that'll need to be a new question with sample data to work with along with expected results.
0

Featured Post

PRTG Network Monitor: Intuitive Network Monitoring

Network Monitoring is essential to ensure that computer systems and network devices are running. Use PRTG to monitor LANs, servers, websites, applications and devices, bandwidth, virtual environments, remote systems, IoT, and many more. PRTG is easy to set up & use.

Join & Write a Comment

Article by: Swadhin
From the Oracle SQL Reference (http://download.oracle.com/docs/cd/B19306_01/server.102/b14200/queries006.htm) we are told that a join is a query that combines rows from two or more tables, views, or materialized views. This article provides a glimps…
This article started out as an Experts-Exchange question, which then grew into a quick tip to go along with an IOUG presentation for the Collaborate confernce and then later grew again into a full blown article with expanded functionality and legacy…
This video shows how to copy a database user from one database to another user DBMS_METADATA.  It also shows how to copy a user's permissions and discusses password hash differences between Oracle 10g and 11g.
This videos aims to give the viewer a basic demonstration of how a user can query current session information by using the SYS_CONTEXT function

746 members asked questions and received personalized solutions in the past 7 days.

Join the community of 500,000 technology professionals and ask your questions.

Join & Ask a Question

Need Help in Real-Time?

Connect with top rated Experts

11 Experts available now in Live!

Get 1:1 Help Now