void MailClient::send( const KPIMIdentities::Identity &identity, const QString &from, const QString &_to, const QString &cc, const QString &subject, const QString &body, bool hidden, bool bccMe, const QString &attachment, const QString &mailTransport ) { Q_UNUSED( identity ); Q_UNUSED( hidden ); #ifdef MAILCLIENTTEST_UNITTEST mUnitTestResult.message = KMime::Message::Ptr(); mUnitTestResult.from.clear(); mUnitTestResult.to.clear(); mUnitTestResult.cc.clear(); mUnitTestResult.bcc.clear(); mUnitTestResult.transportId = -1; #endif if ( !MailTransport::TransportManager::self()->showTransportCreationDialog( 0, MailTransport::TransportManager::IfNoTransportExists ) ) { kError() << "Error while creating transport"; emit finished( ResultErrorCreatingTransport, i18n( "Error while creating transport" ) ); return; } // We must have a recipients list for most MUAs. Thus, if the 'to' list // is empty simply use the 'from' address as the recipient. QString to = _to; if ( to.isEmpty() ) { to = from; } kDebug() << "\nFrom:" << from << "\nTo:" << to << "\nCC:" << cc << "\nSubject:" << subject << "\nBody: \n" << body << "\nAttachment:\n" << attachment << "\nmailTransport: " << mailTransport; QTime timer; timer.start(); MailTransport::Transport *transport = MailTransport::TransportManager::self()->transportByName( mailTransport ); if ( !transport ) { transport = MailTransport::TransportManager::self()->transportByName( MailTransport::TransportManager::self()->defaultTransportName() ); } if ( !transport ) { kError() << "Error fetching transport; mailTransport" << mailTransport << MailTransport::TransportManager::self()->defaultTransportName(); emit finished( ResultErrorFetchingTransport, i18n( "Error fetching transport. Unable to send invitations" ) ); return; } const int transportId = transport->id(); // gather config values KConfig config( QLatin1String( "mailviewerrc" ) ); KConfigGroup configGroup( &config, QLatin1String( "Invitations" ) ); const bool outlookConformInvitation = configGroup.readEntry( "LegacyBodyInvites", #ifdef KDEPIM_ENTERPRISE_BUILD true #else false #endif ); // Now build the message we like to send. The message KMime::Message::Ptr instance // will be the root message that has 2 additional message. The body itself and // the attached cal.ics calendar file. KMime::Message::Ptr message = KMime::Message::Ptr( new KMime::Message ); message->contentTransferEncoding()->clear(); // 7Bit, decoded. // Set the headers message->userAgent()->fromUnicodeString( KProtocolManager::userAgentForApplication( QLatin1String( "KOrganizer" ), QLatin1String( KDEPIMLIBS_VERSION ) ), "utf-8" ); message->from()->fromUnicodeString( from, "utf-8" ); message->to()->fromUnicodeString( to, "utf-8" ); message->cc()->fromUnicodeString( cc, "utf-8" ); if( bccMe ) { message->bcc()->fromUnicodeString( from, "utf-8" ); //from==me, right? } message->date()->setDateTime( KDateTime::currentLocalDateTime() ); message->subject()->fromUnicodeString( subject, "utf-8" ); if ( outlookConformInvitation ) { message->contentType()->setMimeType( "text/calendar" ); message->contentType()->setCharset( "utf-8" ); message->contentType()->setName( QLatin1String( "cal.ics" ), "utf-8" ); message->contentType()->setParameter( QLatin1String( "method" ), QLatin1String( "request" ) ); if ( !attachment.isEmpty() ) { KMime::Headers::ContentDisposition *disposition = new KMime::Headers::ContentDisposition( message.get() ); disposition->setDisposition( KMime::Headers::CDinline ); message->setHeader( disposition ); message->contentTransferEncoding()->setEncoding( KMime::Headers::CEquPr ); message->setBody( KMime::CRLFtoLF( attachment.toUtf8() ) ); } } else { // We need to set following 4 lines by hand else KMime::Content::addContent // will create a new Content instance for us to attach the main message // what we don't need cause we already have the main message instance where // 2 additional messages are attached. KMime::Headers::ContentType *ct = message->contentType(); ct->setMimeType( "multipart/mixed" ); ct->setBoundary( KMime::multiPartBoundary() ); ct->setCategory( KMime::Headers::CCcontainer ); // Set the first multipart, the body message. KMime::Content *bodyMessage = new KMime::Content; KMime::Headers::ContentDisposition *bodyDisposition = new KMime::Headers::ContentDisposition( bodyMessage ); bodyDisposition->setDisposition( KMime::Headers::CDinline ); bodyMessage->contentType()->setMimeType( "text/plain" ); bodyMessage->contentType()->setCharset( "utf-8" ); bodyMessage->contentTransferEncoding()->setEncoding( KMime::Headers::CEquPr ); bodyMessage->setBody( KMime::CRLFtoLF( body.toUtf8() ) ); message->addContent( bodyMessage ); // Set the sedcond multipart, the attachment. if ( !attachment.isEmpty() ) { KMime::Content *attachMessage = new KMime::Content; KMime::Headers::ContentDisposition *attachDisposition = new KMime::Headers::ContentDisposition( attachMessage ); attachDisposition->setDisposition( KMime::Headers::CDattachment ); attachMessage->contentType()->setMimeType( "text/calendar" ); attachMessage->contentType()->setCharset( "utf-8" ); attachMessage->contentType()->setName( QLatin1String( "cal.ics" ), "utf-8" ); attachMessage->contentType()->setParameter( QLatin1String( "method" ), QLatin1String( "request" ) ); attachMessage->setHeader( attachDisposition ); attachMessage->contentTransferEncoding()->setEncoding( KMime::Headers::CEquPr ); attachMessage->setBody( KMime::CRLFtoLF( attachment.toUtf8() ) ); message->addContent( attachMessage ); } } // Job done, attach the both multiparts and assemble the message. message->assemble(); // Put the newly created item in the MessageQueueJob. MailTransport::MessageQueueJob *qjob = new MailTransport::MessageQueueJob( this ); qjob->transportAttribute().setTransportId( transportId ); qjob->sentBehaviourAttribute().setSentBehaviour( MailTransport::SentBehaviourAttribute::MoveToDefaultSentCollection ); const QString unormalizedFrom = ( transport && transport->specifySenderOverwriteAddress() ) ? transport->senderOverwriteAddress() : from; const QString normalizedFrom = KPIMUtils::extractEmailAddress( KPIMUtils::normalizeAddressesAndEncodeIdn( unormalizedFrom ) ); const QString finalFrom = KPIMUtils::extractEmailAddress( normalizedFrom ); qjob->addressAttribute().setFrom( finalFrom ); QStringList toStringList; if( !to.isEmpty() ) { toStringList = extractEmailAndNormalize( to ); qjob->addressAttribute().setTo( toStringList ); } QStringList ccStringList; if( !cc.isEmpty() ) { ccStringList = extractEmailAndNormalize( cc ); qjob->addressAttribute().setCc( ccStringList ); } QStringList bccStringList; if ( bccMe ) { bccStringList = extractEmailAndNormalize( from ); qjob->addressAttribute().setBcc( bccStringList ); } qjob->setMessage( message ); connect( qjob, SIGNAL(finished(KJob*)), SLOT(handleQueueJobFinished(KJob*)) ); qjob->start(); #ifdef MAILCLIENTTEST_UNITTEST mUnitTestResult.message = message; mUnitTestResult.from = finalFrom; mUnitTestResult.to = toStringList; mUnitTestResult.cc = ccStringList; mUnitTestResult.bcc = bccStringList; mUnitTestResult.transportId = transportId; #endif }
/****************************************************************************** * Send the email message specified in an event. * Reply = 1 if the message was sent - 'errmsgs' may contain copy error messages. * = 0 if the message is queued for sending. * = -1 if the message was not sent - 'errmsgs' contains the error messages. */ int KAMail::send(JobData& jobdata, QStringList& errmsgs) { QString err; KPIMIdentities::Identity identity; if (!jobdata.event.emailFromId()) jobdata.from = Preferences::emailAddress(); else { identity = Identities::identityManager()->identityForUoid(jobdata.event.emailFromId()); if (identity.isNull()) { kError() << "Identity" << jobdata.event.emailFromId() << "not found"; errmsgs = errors(i18nc("@info", "Invalid 'From' email address.<nl/>Email identity <resource>%1</resource> not found", jobdata.event.emailFromId())); return -1; } if (identity.emailAddr().isEmpty()) { kError() << "Identity" << identity.identityName() << "uoid" << identity.uoid() << ": no email address"; errmsgs = errors(i18nc("@info", "Invalid 'From' email address.<nl/>Email identity <resource>%1</resource> has no email address", identity.identityName())); return -1; } jobdata.from = identity.fullEmailAddr(); } if (jobdata.from.isEmpty()) { switch (Preferences::emailFrom()) { #ifdef KMAIL_SUPPORTED case Preferences::MAIL_FROM_KMAIL: errmsgs = errors(i18nc("@info", "<para>No 'From' email address is configured (no default email identity found)</para>" "<para>Please set it in <application>KMail</application> or in the <application>KAlarm</application> Configuration dialog.</para>")); break; #endif case Preferences::MAIL_FROM_SYS_SETTINGS: errmsgs = errors(i18nc("@info", "<para>No 'From' email address is configured.</para>" "<para>Please set it in the KDE System Settings or in the <application>KAlarm</application> Configuration dialog.</para>")); break; case Preferences::MAIL_FROM_ADDR: default: errmsgs = errors(i18nc("@info", "<para>No 'From' email address is configured.</para>" "<para>Please set it in the <application>KAlarm</application> Configuration dialog.</para>")); break; } return -1; } jobdata.bcc = (jobdata.event.emailBcc() ? Preferences::emailBccAddress() : QString()); kDebug() << "To:" << jobdata.event.emailAddresses(",") << endl << "Subject:" << jobdata.event.emailSubject(); MailTransport::TransportManager* manager = MailTransport::TransportManager::self(); MailTransport::Transport* transport = 0; if (Preferences::emailClient() == Preferences::sendmail) { kDebug() << "Sending via sendmail"; const QList<MailTransport::Transport*> transports = manager->transports(); for (int i = 0, count = transports.count(); i < count; ++i) { if (transports[i]->type() == MailTransport::Transport::EnumType::Sendmail) { // Use the first sendmail transport found transport = transports[i]; break; } } if (!transport) { QString command = KStandardDirs::findExe(QLatin1String("sendmail"), QLatin1String("/sbin:/usr/sbin:/usr/lib")); transport = manager->createTransport(); transport->setName(QLatin1String("sendmail")); transport->setType(MailTransport::Transport::EnumType::Sendmail); transport->setHost(command); transport->setRequiresAuthentication(false); transport->setStorePassword(false); manager->addTransport(transport); transport->writeConfig(); kDebug() << "Creating sendmail transport, id=" << transport->id(); } } else { kDebug() << "Sending via KDE"; transport = manager->transportByName(identity.transport(), true); if (!transport) { kError() << "No mail transport found for identity" << identity.identityName() << "uoid" << identity.uoid(); errmsgs = errors(i18nc("@info", "No mail transport configured for email identity <resource>%1</resource>", identity.identityName())); return -1; } } kDebug() << "Using transport" << transport->name() << ", id=" << transport->id(); MailTransport::TransportJob* mailjob = manager->createTransportJob(transport->id()); if (!mailjob) { kError() << "Failed to create mail transport job for identity" << identity.identityName() << "uoid" << identity.uoid(); errmsgs = errors(i18nc("@info", "Unable to create mail transport job")); return -1; } KMime::Message message; initHeaders(message, jobdata); err = appendBodyAttachments(message, jobdata); if (!err.isNull()) { kError() << "Error compiling message:" << err; errmsgs = errors(err); return -1; } mailjob->setSender(KPIMUtils::extractEmailAddress(jobdata.from)); mailjob->setTo(jobdata.event.emailPureAddresses()); if (!jobdata.bcc.isEmpty()) mailjob->setBcc(QStringList(KPIMUtils::extractEmailAddress(jobdata.bcc))); mailjob->setData(message.encodedContent()); mJobs.enqueue(mailjob); mJobData.enqueue(jobdata); if (mJobs.count() == 1) { // There are no jobs already active or queued, so send now connect(mailjob, SIGNAL(result(KJob*)), instance(), SLOT(slotEmailSent(KJob*))); mailjob->start(); } return 0; }